前提
・MySQLで「タグを持つ投稿」を取得しています。
・テーブル構造は変えずにお願い致します。
実現したいこと
「指導」というタグを指定しつつ、その投稿が持つ他の「鈴木」「佐藤」というタグも取得したいです。次の結果を目指しています。
comment_id | comment | genre_names | author_name |
---|---|---|---|
1 | 眠らないでください | 指導 | 鈴木,佐藤 |
3 | 席についてください | 指導 | (null) |
発生している問題
「鈴木」「佐藤」というタグが取得されず、次のようにnullとなってしまいます。
comment_id | comment | genre_names | author_name |
---|---|---|---|
1 | 眠らないでください | 指導 | (null) |
3 | 席についてください | 指導 | (null) |
該当のソースコード
テーブル構造です。これは変えたくありません。
SQL
1CREATE TABLE my_comments 2(`ID` int, `comment` varchar(10)); 3INSERT INTO my_comments 4(`ID`, `comment`) 5VALUES 6(1, '眠らないでください'), 7(2, '静かにしてください'), 8(3, '席についてください'), 9(4, 'たまに休んで下さい'); 10 11CREATE TABLE my_tags 12(`ID` int, `tag_kind_id` int, `tag_name` varchar(100)); 13INSERT INTO my_tags 14(`ID`, `tag_kind_id`, `tag_name`) # tag_kind_id=1 なら genre で、tag_kind_id=2 なら author などなど 15VALUES 16(1, 2, '鈴木'), 17(2, 2, '佐藤'), 18(3, 1, '指導'); 19 20CREATE TABLE my_tag_holders 21(`comments_ID` int, `tags_ID` int); 22INSERT INTO my_tag_holders 23(`comments_ID`, `tags_ID`) 24VALUES 25(1, 1),(1, 2),(1, 3), 26(2, 4), 27(3, 3);
問題の生じるSELECT文です。これを改善したいです。
(右記でお試しいただけます → http://sqlfiddle.com/#!9/b95e945/1 )
SQL
1SELECT comments.ID AS comment_id 2 ,comments.comment 3 4 # ジャンル 5 ,GROUP_CONCAT( 6 CASE WHEN tags.tag_kind_id=1 THEN tags.tag_name 7 ELSE null END 8 ) AS genre_names 9 10 # 人 11 ,GROUP_CONCAT( 12 CASE WHEN tags.tag_kind_id=2 THEN tags.tag_name 13 ELSE null END 14 ) AS author_name 15 16FROM my_comments comments 17 LEFT JOIN my_tag_holders th 18 ON th.comments_ID = comments.ID 19 LEFT JOIN my_tags tags 20 ON tags.ID = th.tags_ID 21 22-- タグ名で指定 23WHERE tags.tag_name = '指導' 24GROUP BY comments.ID 25LIMIT 0, 5
試したこと
IDで指定してみると取得できました。
SQL
1-- IDで指定 2WHERE comments.ID IN ( 1, 3 ) 3GROUP BY comments.ID 4LIMIT 0, 5
そのためtag_nameをWHEREに指定する部分が原因だとわかります。
そこで、「もしかして絞り込まれてしまった後に他のタグは取得できないのか?」と考え、絞り込みのためのJOINを追加して次のSELECTを実行したところ、なんとか目的の結果を得ることができました。
SQL
1FROM my_comments comments 2 LEFT JOIN my_tag_holders th 3 ON th.comments_ID = comments.ID 4 LEFT JOIN my_tags tags 5 ON tags.ID = th.tags_ID 6 7 -- 絞り込みのためのJOINを追加 8 LEFT JOIN my_tag_holders th2 9 ON th2.comments_ID = comments.ID 10 LEFT JOIN my_tags tags2 11 ON tags2.ID = th2.tags_ID 12 13-- タグ名で指定 14WHERE tags2.tag_name = '指導' 15GROUP BY comments.ID 16LIMIT 0, 5
しかし、「このようなJOINは二度手間ではないか?」と疑念を持っています。
より正しい方法があるのでは…と質問させて頂きました。
補足情報(FW/ツールのバージョンなど)
MySQLのバージョンはやや古めな5.7を使用しております。
よろしくお願い致します。
その後
INNER JOIN で検索結果を絞る、以下の書き方が最速でした
SQL
1FROM my_comments comments 2 3 INNER JOIN ( 4 5 SELECT comments2.ID 6 FROM my_comments comments2 7 LEFT JOIN my_tag_holders th2 8 ON th2.comments_ID = comments2.ID 9 LEFT JOIN my_tags tags2 10 ON tags2.ID = th2.tags_ID 11 12 -- タグ名で指定 13 WHERE tags2.tag_name = '指導' 14 GROUP BY comments2.count_likes, comments2.ID 15 ORDER BY comments2.count_likes DESC, comments2.ID DESC 16 LIMIT 0, 20 17 18 ) AS searched ON searched.ID = comments.ID 19 20 LEFT JOIN my_tag_holders th 21 ON th.comments_ID = comments.ID 22 LEFT JOIN my_tags tags 23 ON tags.ID = th.tags_ID 24 25GROUP BY searched.ID 26ORDER BY comments.count_likes DESC, comments.ID DESC 27LIMIT 0, 20
回答2件
あなたの回答
tips
プレビュー