- ベストアンサー
WordPressの質問(q10279843)の続
カラム名 question を text にしたい場合下記コードを変更しても良いでしょうか? bbs_quest_input.php の101行目 name="question" bbs_quest_input.php の214行目 var question_value = ""; bbs_quest_input.php の335行目 if (!['name', 'title', 'question'].includes(e.target.id)) return; bbs_quest_input.php の364行目 question_value = ""; bbs_quest_input.php の390行目 question_value = json.question; ※最新コード https://wandbox.org/permlink/PjhrH75IR9jUMnpL
- みんなの回答 (42)
- 専門家の回答
質問者が選んだベストアンサー
・ファイルを右クリックしたときに有効になる設定を作成することが出来るという記事を見つけて試しておりました。 そうでしたか。 ポータブルモードで使う必要はないと思いますので、 通常でインストールしてください。 回答No.41の添付画像のように、 コンテキストメニューに追加するよう、 チェックボックスをオンにしていただければいいと思います。
その他の回答 (41)
- dell_OK
- ベストアンサー率13% (766/5720)
・SQL を実行したところエラーが発生しており WITHの定義しかないからです。 元のように以下の行を追加してください。 SELECT * FROM threads ORDER BY top_id DESC, path
補足
回答ありがとうございます、コードを加えて実行したところ下記画像のように表示されました。 https://imgur.com/a/DYLOiE9.png
- dell_OK
- ベストアンサー率13% (766/5720)
➀ CAST(id AS CHAR(255)) AS path, は id を CHAR型に変更しているということでしょうか? そうです。 VARCHARとの違いは参考サイトにある通りです。 ここをVARCHARにしても同じ結果になりそうな気はします。 CHARにされているのは書いた人に理由を聞いてみないことにはわからないですね。 ➁ 0 AS depth というコードは回答されるたびに深さを保存するような役割があるのでしょうか? 深さが0と言う事は、それが始まり、つまり親(質問)ということになります。 UNIONより上のSELECTはWHERE parent_id IS NULLとなっているように親(質問)を取得するためのものです。 ➂ UNION ALL 後のコードについてお聞きしたいのですが、messages テーブルのカラムと自分(threads)のカラムが混ざっているのは何故でしょうか? ➃ t.depth + 1 AS depth はどのような意味のコードになるのでしょうか? UNIONより下のmessagesは子(返信)を取得するためのものです。 なので基本的に抽出する項目は子(自分)の内容です。 ではthreadsは何かというとその子の直近の親(質問、返信)です。 ON m.parent_id = t.id 子(messages)のparent_idと紐づく親(threads)のidです。 無限に子を取得していくと言っても、親から直接孫をみたりはせず、親と子の紐づけしか必要ではなく、それを繰り返し見ていくというだけのことです。 必要なのは直近の親の存在だけです。 なので直近の親(threads)が混ざっています。 t.top_id 親のID t.depth + 1 親の深さ+1つまり子(自分)の深さ ですね。 ちょっと難しいのがここですね。 CONCAT(t.path, '-', m.id) AS path CONCATは文字列の結合です。 t.path(親のpath)と'-'とm.is(子(自分)のID)を結合しています。 これがこのSQLの中で最も重要と言っていいほどに無限に繰り返されることの証拠にもなります。 pathはは家系図だと思ってください。 SQLを実行した時に確認した「1」「1-2」「1-2-4」とかです。 -がない「1」はUNIONより上の親(質問)で、①で出てきた、CAST(id AS CHAR(255)) AS path,です。 -があるのはUNIONより下のpathです。 文字列で-を結合していますからね。 子(自分)のIDが「2」のデータから見た親はID「1」でしたね。 INSERT INTO sortable (ID, parent_id, content) VALUES (2, 1, 'これは親メッセージへの返信です'); ID「1」のデータは親IDがNULLでしたので親(質問)で、つまりUNIONより上ですね。 INSERT INTO sortable (ID, parent_id, content) VALUES (1, NULL, 'これは親メッセージです'); と言う事は、ID「2」からみたthreadsのpathは「1」で、それに子(自分)のIDを-でつなげたものが自分のpathで「1-2」となりました。 次に、ID「4」からみた親はID「2」です。 INSERT INTO sortable (ID, parent_id, content) VALUES (4, 2, 'これは最初の返信への返信です'); ID「2」のpathは「1-2」でしたから、ここに子(自分)のIDを-でつなげると「1-2-4」になります。 親から受け継いだpathにひたすら-と自分のIDをつなげて子に渡していく、ようなイメージですね。 先ほどの子(自分)の深さも同じようにひたすらに1を+していくことになります。 深さと-の数は等しいとも言えます。
お礼
こちらが最新の回答になります。 SQL を実行したところエラーが発生しており、原因を調べてみたのですがどこが間違っているのか分からない状態です。 アドバイスお願い致します。 ※表示されているエラー内容 式が必要です。 (near ";" at position 518) WITH CTE が予期せず終了しました。 (near ";" at position 518) ※データベース画像 https://imgur.com/bjtl60g ※該当コード WITH RECURSIVE threads AS ( SELECT id, parent_id, content, created_at, id AS top_id, CAST(id AS CHAR(255)) AS path, 0 AS depth FROM messages WHERE parent_id IS NULL UNION ALL SELECT m.id, m.parent_id, m.content, m.created_at, t.top_id, CONCAT(t.path, '-', m.id) AS path, t.depth + 1 AS depth FROM messages m INNER JOIN threads t ON m.parent_id = t.id )
補足
Q.深さが0と言う事は、それが始まり、つまり親(質問)ということになります。 UNIONより上のSELECTはWHERE parent_id IS NULLとなっているように親(質問)を取得するためのものです。 A.回答ありがとうございます、深さが0というのは親のことだったんですね…理解出来ました。 Q.UNIONより下のmessagesは子(返信)を取得するためのものです。 なので基本的に抽出する項目は子(自分)の内容です。 ではthreadsは何かというとその子の直近の親(質問、返信)です。 ON m.parent_id = t.id 子(messages)のparent_idと紐づく親(threads)のidです。 無限に子を取得していくと言っても、親から直接孫をみたりはせず、親と子の紐づけしか必要ではなく、それを繰り返し見ていくというだけのことです。 必要なのは直近の親の存在だけです。 なので直近の親(threads)が混ざっています。 t.top_id 親のID t.depth + 1 親の深さ+1つまり子(自分)の深さ ですね。 A.回答ありがとうございます、messages が親で threads が子で UNION より下の messages は孫のような感じで考えております。 t.top_id 親のID についてお聞きしたいのですが、何故 threads テーブルで id AS top_id,としたか分かりますでしょうか? そのまま id, と使えるのではないかと思いました。 Q.ちょっと難しいのがここですね。 CONCAT(t.path, '-', m.id) AS path CONCATは文字列の結合です。 t.path(親のpath)と'-'とm.is(子(自分)のID)を結合しています。 SQLを実行した時に確認した「1」「1-2」「1-2-4」とかです。 -がない「1」はUNIONより上の親(質問)で、①で出てきた、CAST(id AS CHAR(255)) AS path,です。 -があるのはUNIONより下のpathです。 先ほどの子(自分)の深さも同じようにひたすらに1を+していくことになります。 深さと-の数は等しいとも言えます。 A.解説ありがとうございます、CONCAT(t.path, '-', m.id) AS path を見ると m = messages が使われているため、messages が親と考えるのは間違っているようですね… 考え方として messages はどのような立ち位置になるのでしょうか…? 親(回答)+1した数字が子(返信)という認識でした、必ずしもそうならないという解釈で合ってますでしょうか?
- dell_OK
- ベストアンサー率13% (766/5720)
・親(質問)と子(回答、返信)でカラム構成が違う場合に内部結合する際は下記のようになるのではないかと考えておりました。 そうですね。 あっています。 通常の JOIN であればそのようにするのが一般的でだと思います。 ・nullを含んだテーブルの検索はエラーを起こすこともあるようなので使わないほうが良いのでしょうか? NULLについては人によって意見がわかれるところだと思います。 エラーを起こさないようにしていれば問題ありません。 例えば、とある名簿のテーブルがあるとします。 名簿なので人の情報がいろいろとあります。 名前や生年月日などがカラムとしてありますが、死亡年月日もあるとします。 その人が生きている間は死亡年月日に何も入れることはできません。 このような場合は NULL を使うのがふさわしいでしょう。 それで、名簿一覧表を出力する時に NULL を YYYY年MM月DD日 の書式編集するとエラーになる言語もあります。 なので NULL の時は空欄にするとかの配慮が必要です。 このような対応さえしておけば NULL をおそれることはありません。 対応し忘れていたとしても、開発時にすぐにエラーが発生する場合が多いような気がします。 もちろん設計時にきちんと考えておいて忘れないことが重要です。 一方 NULL を否定する人もいるかも知れず。 あえてその理由をむりやりに考えてみると。 そんなの生年月日と同じの入れとけばいいじゃん。 生年月日と同じなら表示しないという処理で対応すればいいじゃん。 みたいな感じになるかも知れません。 でも、例えば、生まれたその日に死んでしまった赤ちゃん、とかを想定すると、生年月日と死亡年月日が一緒なのって、死んだのか死んでないのかわからないですよね。 じゃあ、生年月日の前日を入れとけばいいじゃん。 とか、もうその人の情報としてはウソの内容になってしまったりします。 これは日付を日付型のカラムにした場合の話しなので、日付をINT型のカラムにしていれば、0を入れとけばいいじゃん、みたいなことにもなります。 他には、そのデータベースで日付型の最小値を入れるとかもあります。 ですが、データベースごとや日付型の種類によってもその最小値が異なったりします。 https://www.idearu.info/article/data/ds1116 なので、プログラム言語側で調整しないといけませんし、データベースを他のデータベースに移行するとかになると、これまた手間がかかります。 結局 NULL は必要に応じて使う、が私はいいと思っています。 カラムに NULL を入れないとしても、他のことで NULL が発生することはありますので、あまり NULL にこだわることもないのかなと思います。 他のことの NULL の例としては、LEFT JOIN した右側のテーブルは NULL になるとかです。 質問と回答を LEFT JOIN した時に回答がなければ、回答のカラムは NULL です。 それに、これはあまり重要ではないかも知れませんが、データベースについていろいろと考えた「エドガー・フランク・コッド」は「規則 3 null値を体系的に扱う」と言っています。 https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%83%E3%83%89%E3%81%AE12%E3%81%AE%E8%A6%8F%E5%89%87 NULL あってのデータベースなので使わない方がおかしいのかも知れません。
補足
Q.これは日付を日付型のカラムにした場合の話しなので、日付をINT型のカラムにしていれば、0を入れとけばいいじゃん、みたいなことにもなります。 他には、そのデータベースで日付型の最小値を入れるとかもあります。 ですが、データベースごとや日付型の種類によってもその最小値が異なったりします。 https://www.idearu.info/article/data/ds1116 なので、プログラム言語側で調整しないといけませんし、データベースを他のデータベースに移行するとかになると、これまた手間がかかります。 結局 NULL は必要に応じて使う、が私はいいと思っています。 カラムに NULL を入れないとしても、他のことで NULL が発生することはありますので、あまり NULL にこだわることもないのかなと思います。 他のことの NULL の例としては、LEFT JOIN した右側のテーブルは NULL になるとかです。 質問と回答を LEFT JOIN した時に回答がなければ、回答のカラムは NULL です。 それに、これはあまり重要ではないかも知れませんが、データベースについていろいろと考えた「エドガー・フランク・コッド」は「規則 3 null値を体系的に扱う」と言っています。 https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%83%E3%83%89%E3%81%AE12%E3%81%AE%E8%A6%8F%E5%89%87 NULL あってのデータベースなので使わない方がおかしいのかも知れません。 A.回答ありがとうございます、データベースごとや日付型の種類によってもその最小値が異なったりする為、 NULL は必要に応じて使うほうが良いという事で覚えておきます。 NULL はエラーを起こさないようにしていれば問題ないということで安心いたしました。
- dell_OK
- ベストアンサー率13% (766/5720)
それでと。 SQL文の段階説明のためにあえて親子を横並びに抽出する連結を試していただきました。 もう少し説明するつもりでしたが、質問者さまの方で3つ連結されたので、話しをだいぶ先に進められます。 ひ孫になると4つを連結することになりますし、さらにその先もあります。 しかしながら、無限階層を想定しているためと言って、無限に子孫を横並びに連結するわけにはいきません。 無限に子を抽出する方法としては、連結はせず、SQLを実行して子があればまたSQLを実行してまたその子があればSQLを実行して、と言うループ処理にする方法もあります。 ですが、親子だけでなく兄弟関係もあるのでそれも考えると、兄弟階層まで戻ってSQLを実行するとかややこしくなります。 そこで登場するのが WITH RECURSIVE です。 RECURSIVE は再帰的と言う意味です。 再帰的とは「自分自身を繰り返す」と言うような意味があると思ってください。 「自分自身を繰り返す」だけで無限が実現できます。 鏡と鏡を向かい合わせるとそこに映るのは無限の鏡、みたいな感じですね。 これは横並びに連結するのではなく、縦並びに連結して実現します。 カラム方向へのループは難しいですが、行方向へのループはそれほどではありません。 カラム方向であれば、不要なカラムを消して取得することも考えられます。 しかしながら行方向に取得するのはすべて同じカラム構成になります。 行ごとにカラム数が違うものを取得することはできません。 なので、使わないからと言って回答(返信)のタイトルとスタンプ画像を取得しないわけにはいかないのです。 もし似たようなことをするとしたら、カラムはあるけど NULL として取得する方法です。 実際にデータを取得するよりは負荷を軽減できるかも知れませんので。 では、SQL文に戻って、 再帰的に自分自身を繰り返しているのがどこかを見てみましょう。 自分とは threads のことです。 WITH のところで定義された名前ですね。 WITH RECURSIVE threads AS ( SELECT id, parent_id, content, created_at, id AS top_id, CAST(id AS CHAR(255)) AS path, 0 AS depth FROM messages WHERE parent_id IS NULL UNION ALL SELECT m.id, m.parent_id, m.content, m.created_at, t.top_id, CONCAT(t.path, '-', m.id) AS path, t.depth + 1 AS depth FROM messages m INNER JOIN threads t ON m.parent_id = t.id ) そして再登場するのが最後に INNER JOIN している threads です。 WITH で定義したものが、その定義のカッコ内に登場しています。 最終的に実行されるSQLはここです。 SELECT * FROM threads ORDER BY top_id DESC, path threads を参照しています。 でその threads はなにかと言うと、WITH で定義されているカッコの中のもの。 カッコの中では、また threads が JOIN され参照されています。 でその threads はなにかというと、WITH で定義されているカッコの中のもの。 カッコの中では、また threads が JOIN され参照されています・・・・・・。 と無限に JOIN され参照されます。 こう説明文を書いてて無限がおそろしいものに思えてきました。 結局、無限とは言ってもいつまで繰り返してくれるのか、と言うことですが、実際はデータがなくなるまでです。
補足
Q.そこで登場するのが WITH RECURSIVE です。 RECURSIVE は再帰的と言う意味です。 再帰的とは「自分自身を繰り返す」と言うような意味があると思ってください。 「自分自身を繰り返す」だけで無限が実現できます。 鏡と鏡を向かい合わせるとそこに映るのは無限の鏡、みたいな感じですね。 A.解説ありがとうございます、WITH RECURSIVE で無限に繰り返すということで覚えておきます。 Q.カラム方向であれば、不要なカラムを消して取得することも考えられます。 しかしながら行方向に取得するのはすべて同じカラム構成になります。 行ごとにカラム数が違うものを取得することはできません。 なので、使わないからと言って回答(返信)のタイトルとスタンプ画像を取得しないわけにはいかないのです。 もし似たようなことをするとしたら、カラムはあるけど NULL として取得する方法です。 実際にデータを取得するよりは負荷を軽減できるかも知れませんので。 A.解説ありがとうございます、なるほどそのような理由からカラム数を同じに設定するんですね。 1つ dell_ok さんにお聞きしておきたかったのですが、nullを含んだテーブルの検索はエラーを起こすこともあるようなので使わないほうが良いのでしょうか? ※データベースで null は極力さけるべき https://oshiete.goo.ne.jp/qa/7902714.html Q.再帰的に自分自身を繰り返しているのがどこかを見てみましょう。 自分とは threads のことです。 WITH のところで定義された名前ですね。 WITH RECURSIVE threads AS ( SELECT id, parent_id, content, created_at, id AS top_id, CAST(id AS CHAR(255)) AS path, /* 1つのデータ型を互換性のある別のデータ型に変換 */ 0 AS depth /* 再帰の深さを格納する */ FROM messages WHERE parent_id IS NULL UNION ALL /* UNION ALL:重複した行を含める(重複がある場合もすべて統合する)*/ SELECT m.id, m.parent_id, m.content, m.created_at, t.top_id, CONCAT(t.path, '-', m.id) AS path, t.depth + 1 AS depth FROM messages m INNER JOIN threads t ON m.parent_id = t.id ) A.コードありがとうございます。 複数理解できないことがあるので教えて頂きたいです。 ➀ CAST(id AS CHAR(255)) AS path, は id を CHAR型に変更しているということでしょうか? 調べてみたのですがCHAR型とVARCHAR型の違いがよく分かりませんでした… ※参考サイト https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0041 ➁ 0 AS depth というコードは回答されるたびに深さを保存するような役割があるのでしょうか? ➂ UNION ALL 後のコードについてお聞きしたいのですが、messages テーブルのカラムと自分(threads)のカラムが混ざっているのは何故でしょうか? ➃ t.depth + 1 AS depth はどのような意味のコードになるのでしょうか? Q.最終的に実行されるSQLはここです。 SELECT * FROM threads ORDER BY top_id DESC, path threads を参照しています。 でその threads はなにかと言うと、WITH で定義されているカッコの中のもの。 カッコの中では、また threads が JOIN され参照されています。 でその threads はなにかというと、WITH で定義されているカッコの中のもの。 カッコの中では、また threads が JOIN され参照されています・・・・・・。 と無限に JOIN され参照されます。 こう説明文を書いてて無限がおそろしいものに思えてきました。 結局、無限とは言ってもいつまで繰り返してくれるのか、と言うことですが、実際はデータがなくなるまでです。 A.解説ありがとうございます、WITH RECURSIVE threads で再帰的に自分自身を繰り返していて、それをデータがなくなるまで無限に実行しているということですね。
- dell_OK
- ベストアンサー率13% (766/5720)
・回答(返信)のみタイトルとスタンプ画像をなくしたい場合は内部結合の際に SELECT から消しても良いでしょうか? 消さなくていいと思います。 消したい理由はわかりませんが、 そのふたつの項目をなくしたところでサーバーにかかる負荷が変わるほどのことはありません。 使いたくなったときに直さないといけなくなるので消さない方がいいかも知れません。 このSQL文の説明のずっと先にいくとわかってくると思いますが、消せなくなります。 なので、いまは、実際のサイトのこととまじえて考えなくてもいいと思います。 ・更に内部連結を1つ増やして3つを連結するという形で合ってますでしょうか? そうですね。 3つを連結されるのは予想外でしたが、とてもいいことでよかったす。 JOIN ごとに ON が必要なので最後のところはこうですね。 SELECT * FROM oya LEFT JOIN ko ON oya.id = ko.parent_id (親に紐づいた子) LEFT JOIN mago ON ko.id = mago.parent_id (子に紐づいた孫) ここで WITH が便利なことを説明しておきます。 ko と mago の SELECT はまったく同じです。 まったく同じ SELECT のために WITH があると言ってもいいくらいです。 どう言うことかと言うと、mago は定義が不要です。 ko を mago として使えるからです。 WITH oya AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) , ko AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) SELECT * FROM oya LEFT JOIN ko ON oya.id = ko.parent_id LEFT JOIN ko AS mago (子を孫として使う) ON ko.id = mago.parent_id
補足
Q.回答(返信)のみタイトルとスタンプ画像をなくしたい場合は内部結合の際に SELECT から消しても良いでしょうか? A.回答ありがとうございます、説明不足で申し訳ありません。 親(質問)と子(回答、返信)でカラム構成が違う場合に内部結合する際は下記のようになるのではないかと考えておりました。 ※親テーブル例 SELECT id, parent_id, content, created_at title stamp FROM messages WHERE parent_id IS NULL ※子テーブル例 SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL Q.そのふたつの項目をなくしたところでサーバーにかかる負荷が変わるほどのことはありません。 使いたくなったときに直さないといけなくなるので消さない方がいいかも知れません。 このSQL文の説明のずっと先にいくとわかってくると思いますが、消せなくなります。 なので、いまは、実際のサイトのこととまじえて考えなくてもいいと思います。 A.アドバイスありがとうございます。消さないほうが良いということで覚えておきます。 Q.ここで WITH が便利なことを説明しておきます。 ko と mago の SELECT はまったく同じです。 まったく同じ SELECT のために WITH があると言ってもいいくらいです。 どう言うことかと言うと、mago は定義が不要です。 ko を mago として使えるからです。 A.解説ありがとうございます、テーブルカラムが同一であれば省略できるのですね勉強になりました。
- dell_OK
- ベストアンサー率13% (766/5720)
参考サイトのSQL文でどのように紐づけられているかを、 部分的に簡単なSQL文で段階をおって説明していきたいと思います。 親(質問)だけを抽出してみましょう。 SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL 結果はこんな感じになると思います。 id parent_id content created_at 1 « NULL » これは親メッセージです 2024/09/06 9:08:53 5 « NULL » これは別の親メッセージです 2024/09/06 9:08:53 子(返信)だけを抽出してみましょう。 SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL 結果はこんな感じになると思います。5件あります。 id parent_id content created_at 2 1 これは親メッセージへの返信です 2024/09/06 9:08:53 3 1 親メッセージへの別の返信です 2024/09/06 9:08:53 4 2 これは最初の返信への返信です 2024/09/06 9:08:53 6 5 2つ目の親メッセージへの返信です 2024/09/06 9:08:53 7 6 2つ目の親メッセージの返信への返信です 2024/09/06 9:08:53 親(質問)と子(返信)を紐づけて抽出してみましょう。 SELECT * FROM ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) AS oya INNER JOIN ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) AS ko ON oya.id = ko.parent_id 「ON oya.id = ko.parent_id」が親子の紐づけです。 親のIDと、子が持っている親のIDをつなげています。 結果はこんな感じになると思います。 id parent_id content created_at id parent_id content created_at 1 « NULL » これは親メッセージです 2024/09/06 9:08:53 2 1 これは親メッセージへの返信です 2024/09/06 9:08:53 1 « NULL » これは親メッセージです 2024/09/06 9:08:53 3 1 親メッセージへの別の返信です 2024/09/06 9:08:53 5 « NULL » これは別の親メッセージです 2024/09/06 9:08:53 6 5 2つ目の親メッセージへの返信です 2024/09/06 9:08:53 子は5件あるはずですが、3件分しか抽出できていません。 これでは親(質問)直下の子(返信)しか抽出できないからです。 このSQL文はこんな風に書きかえることができます。 WITH oya AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) , ko AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) SELECT * FROM oya LEFT JOIN ko ON oya.id = ko.parent_id WITH で抽出するSQL文を前もってまとめて定義しておくことができます。 一番下の SELECT が最終的に実行されるSQL文です。 すっきりして、少しは読みやすくなったかと思います。 こちらも実行してみておいてください。 続きは後日。
補足
Q.親(質問)だけを抽出してみましょう。 SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL A.回答ありがとうございます理解出来ました。 CREATE TABLE~FOREIGN KEY (parent_id) REFERENCES messages(id) で親子関係を INSERT INTO で全体のテーブル構成を作っていたんですね。 同一テーブルでの紐付けはIDと親ID それぞれ内部でカラムを作って結合させるという感じでイメージしております。 回答(返信)のみタイトルとスタンプ画像をなくしたい場合は内部結合の際に SELECT から消しても良いでしょうか? Q.親(質問)と子(返信)を紐づけて抽出してみましょう。 SELECT * FROM ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) AS oya INNER JOIN ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) AS ko ON oya.id = ko.parent_id 「ON oya.id = ko.parent_id」が親子の紐づけです。 親のIDと、子が持っている親のIDをつなげています。 A.解説ありがとうございます、返信 ID (comment_id) をこのテーブルに加えたい場合は更に内部連結を1つ増やして3つを連結するという形で合ってますでしょうか? 親のIDと、子が持っている親のID ということは返信 ID(孫)を追加する際は parent_id も必要ということで考えております。 ※ SQL 実行結果 https://imgur.com/J2QHRJT.png ※返信 IDをテーブルに加えてみました。 SELECT * FROM ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) AS oya INNER JOIN ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) INNER JOIN ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) AS ko ON oya.id = ko.parent_id ※返信(孫)を書き換えてみました。 WITH oya AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NULL ) , ko AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) , mago AS ( SELECT id, parent_id, content, created_at FROM messages WHERE parent_id IS NOT NULL ) SELECT * FROM oya LEFT JOIN ko LEFT JOIN mago ON oya.id = ko.parent_id = mago.parent_id
- dell_OK
- ベストアンサー率13% (766/5720)
SELECT してみて、添付画像のような結果になりましたか。
補足
回答ありがとうございます。同じものが表示されております。 ※テーブル https://imgur.com/OKkFB5W.png
- dell_OK
- ベストアンサー率13% (766/5720)
・同一テーブルのカラムはどのように紐づけるのでしょうか? その前に、回答No.2の補足に書かれた参考サイトのSQLを実行してみましたか。 まだでしたら実行して確認しておきましょう。 大きく分けて CREATE と INSERT と SELECT です。
補足
回答ありがとうございます。試してみたのですがよく分からない状態です… CREATE がテーブル生成で INSERT が親子関係の成立で SELECT がカラムの選択でしょうか? 紐付けは INSERT ではないかと考えております。
- dell_OK
- ベストアンサー率13% (766/5720)
・親IDが NULL(紐づけられていない)のものというのはどういう意味でしょうか? イメージ図にIDと親IDを追記してみました。 ※以後、質問IDとは呼ばずに単にIDと呼ぶことにしましょう。 質問(ID:1、親ID:NULL) ┣返信(ID:2、親ID:1) ┃┗返信(ID:3、親ID:2) ┃ ┗返信(ID:4、親ID:3) ┣返信(ID:5、親ID:1) ┃┣返信(ID:6、親ID:5) ┃┃┗返信(ID:7、親ID:6) ┃┗返信(ID:8、親ID:5) ┗返信(ID:9、親ID:1) 親IDがNULL(紐づくものがない)なので質問です。 返信の親IDは直近の上階層のIDです。 これが親と紐づいているということになります。 返信のIDはここでは上から順にカウントアップしています。 実際は投稿された順のIDになります。 ・参考サイトから質問IDを親IDに設定した後、どのカラムと紐づけられていないか確認するのでしょうか? 参考サイトは別テーブルでの親子関係なのでカラム名が同じで書かれています。 両用テーブルでひとつのテーブルにしたので、IDを意図するものがIDと親IDのふたつのカラム名になります。 IDと親IDで紐づけます。 ・以前他の方からアドバイス頂いたテーブル例では parent_id を親IDとして追加しているのですが、こちらの SQL との違いは分かりますでしょうか? たぶん同じだと思います。 INSERTしたデータをイメージ図に当てはめるとこんな感じです。 'これは親メッセージです'(1, NULL) ┣'これは親メッセージへの返信です'(2, 1) ┃┗'これは最初の返信への返信です'(4, 2) ┗'親メッセージへの別の返信です'(3, 1) 'これは別の親メッセージです'(5, NULL) ┗'2つ目の親メッセージへの返信です'(6, 5) ┗'2つ目の親メッセージの返信への返信です'(7, 6) IDと親IDの関係が同じであることがわかるでしょうか。 なのでSQLは同じような感じになると思います。
補足
Q.両用テーブルでひとつのテーブルにしたので、IDを意図するものがIDと親IDのふたつのカラム名になります。 IDと親IDで紐づけます。 A.回答ありがとうございます。同一テーブルのカラムはどのように紐づけるのでしょうか? テーブルが2つ無い場合のカラムの結合の仕方を調べてみたのですが分かりませんでした。 Q.たぶん同じだと思います。 INSERTしたデータをイメージ図に当てはめるとこんな感じです。 'これは親メッセージです'(1, NULL) ┣'これは親メッセージへの返信です'(2, 1) ┃┗'これは最初の返信への返信です'(4, 2) ┗'親メッセージへの別の返信です'(3, 1) 'これは別の親メッセージです'(5, NULL) ┗'2つ目の親メッセージへの返信です'(6, 5) ┗'2つ目の親メッセージの返信への返信です'(7, 6) IDと親IDの関係が同じであることがわかるでしょうか。 なのでSQLは同じような感じになると思います。 A.解説ありがとうございます、図を見たところ理解することが出来ました。IDと親IDと返信IDのカラムを紐付けるということですね。 カラムを紐付けるところが分からず、テーブルの構成のみ書きました。 CREATE TABLE `sortable` ( `ID` bigint(20) INT AUTO_INCREMENT PRIMARY KEY, `parent_id` bigint(20) INT NULL, `TS` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `content TEXT` varchar(500) INT NULL, `title` varchar(255) INT NULL, `name` varchar(255) INT NULL, `stamp` INT (11) NOT NULL, `select` INT (11) NOT NULL, `unique_id` varchar(36) NOT NULL uuid() UNIQUE KEY, `ip` varchar(39) INT NULL, `attach1` varchar(255) INT NULL, `attach2` varchar(255) INT NULL, `attach3` varchar(255) INT NULL, `usericon` varchar(255) INT NULL, `comment_id` bigint(20) INT NULL, FOREIGN KEY (parent_id) REFERENCES sortable(id) ); INSERT INTO sortable (ID, parent_id, content) VALUES (1, NULL, 'これは親メッセージです'); INSERT INTO sortable (ID, parent_id, content) VALUES (2, 1, 'これは親メッセージへの返信です'); INSERT INTO sortable (ID, parent_id, content) VALUES (3, 1, '親メッセージへの別の返信です'); INSERT INTO sortable (ID, parent_id, content) VALUES (4, 2, 'これは最初の返信への返信です'); INSERT INTO sortable (ID, parent_id, content) VALUES (5, NULL, 'これは別の親メッセージです'); INSERT INTO sortable (ID, parent_id, content) VALUES (6, 5, '2つ目の親メッセージへの返信です'); INSERT INTO sortable (ID, parent_id, content) VALUES (7, 6, '2つ目の親メッセージの返信への返信です');
- dell_OK
- ベストアンサー率13% (766/5720)
そうですね。 それではいまのところは無限階層を想定して取り組む方向で進めていきましょう。 目に見える部分や使い方は質問者さまの要望をなるべく備えた方がいいでしょう。 ツリー型は自由に枝わかれできるので、以下のような図をイメージしておくといいと思います。 質問 ┣返信 ┃┗返信 ┃ ┗返信 ┣返信 ┃┣返信 ┃┃┗返信 ┃┗返信 ┗返信 bbs_quest_input.php にもう2か所 text にするところがあります。 text_value = json.question; ↓ text_value = json.text; child.appendChild(document.createTextNode(question_value)); //孫要素として Text ノードを生成 ↓ child.appendChild(document.createTextNode(text_value)); //孫要素として Text ノードを生成 これで、質問の投稿はできるようになると思います。
補足
回答ありがとうございます。dell_ok さんに教えて頂いた方法②についてどうすれば良いか分からないので教えて欲しいです。 前提としてどの質問に対しての回答なのか紐づけのために質問ID(親ID)を設定する。ということだったと思うのですが、親IDが NULL(紐づけられていない)のものというのはどういう意味でしょうか? 参考サイトから質問IDを親IDに設定した後、どのカラムと紐づけられていないか確認するのでしょうか? イメージでは質問IDというのは回答と両用テーブルになったことで、質問、回答、返信IDとして扱うことになっており、質問のみを判定するという事だと思うのですが… 方法② 親IDが NULL(紐づけられていない)のものを質問として、親IDが設定されているものを回答とする。 ※参考サイト https://dream-database-sql-seminar.com/mysql-basic-contents/mb_ch05/mb_0502/#:~:text=%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6%E3%81%AF%E3%80%81%E5%90%84,%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%EF%BC%89%E3%81%A8%E5%91%BC%E3%81%B3%E3%81%BE%E3%81%99%E3%80%82 ___________________________________________________________ 以前他の方からアドバイス頂いたテーブル例では parent_id を親IDとして追加しているのですが、こちらの SQL との違いは分かりますでしょうか? ※テーブル例 CREATE TABLE messages ( id INT AUTO_INCREMENT PRIMARY KEY, parent_id INT NULL, content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (parent_id) REFERENCES messages(id) ); INSERT INTO messages (id, parent_id, content) VALUES (1, NULL, 'これは親メッセージです'); INSERT INTO messages (id, parent_id, content) VALUES (2, 1, 'これは親メッセージへの返信です'); INSERT INTO messages (id, parent_id, content) VALUES (3, 1, '親メッセージへの別の返信です'); INSERT INTO messages (id, parent_id, content) VALUES (4, 2, 'これは最初の返信への返信です'); INSERT INTO messages (id, parent_id, content) VALUES (5, NULL, 'これは別の親メッセージです'); INSERT INTO messages (id, parent_id, content) VALUES (6, 5, '2つ目の親メッセージへの返信です'); INSERT INTO messages (id, parent_id, content) VALUES (7, 6, '2つ目の親メッセージの返信への返信です'); ※SELECTの例 WITH RECURSIVE threads AS ( SELECT id, parent_id, content, created_at, id AS top_id, CAST(id AS CHAR(255)) AS path, 0 AS depth FROM messages WHERE parent_id IS NULL UNION ALL SELECT m.id, m.parent_id, m.content, m.created_at, t.top_id, CONCAT(t.path, '-', m.id) AS path, t.depth + 1 AS depth FROM messages m INNER JOIN threads t ON m.parent_id = t.id ) SELECT * FROM threads ORDER BY top_id DESC, path
お礼
回答ありがとうございます、返事が遅れてしまい申し訳ありません。 1つ問題がありまして、通常でインストールした場合ファイルやフォルダの中のソースファイルを開くことが出来ません。 フォルダやファイルから開く必要はないのでしょうか? 質問の期限が切れてしまったので下記リンクからアドバイス宜しくお願い致します。 ※新しい質問 https://okwave.jp/qa/q10297398.html