- 締切済み
指定された趣味を持つメンバーがいるグループを抽出するSQL
グループテーブル、メンバーテーブル、趣味テーブルの3つのテーブルがあります。 あるメンバーはあるグループに属しており、趣味を1つ持っています。 以下がそのSQLです。 CREATE TABLE groups ( g_id int primary key ); CREATE TABLE members ( m_id int primary key , g_id int , h_id int ); CREATE TABLE hobbies ( h_id int primary key, h_name text ); INSERT INTO groups VALUES ( 1 ); INSERT INTO groups VALUES ( 2 ); INSERT INTO groups VALUES ( 3 ); INSERT INTO members VALUES ( 1, 1, 1); INSERT INTO members VALUES ( 2, 1, 3); INSERT INTO members VALUES ( 3, 1, 4); INSERT INTO members VALUES ( 4, 1, 4); INSERT INTO members VALUES ( 5, 2, 1); INSERT INTO members VALUES ( 6, 2, 2); INSERT INTO members VALUES ( 7, 2, 3); INSERT INTO members VALUES ( 8, 3, 2); INSERT INTO members VALUES ( 9, 3, 3); INSERT INTO members VALUES ( 10, 3, 4); INSERT INTO hobbies VALUES ( 1, 'sports' ); INSERT INTO hobbies VALUES ( 2, 'music' ); INSERT INTO hobbies VALUES ( 3, 'book' ); INSERT INTO hobbies VALUES ( 4, 'drive' ); 指定された趣味を持つメンバーがいるグループを抽出するにはどうすればいいでしょうか? 例えば、「読書が趣味なメンバーとドライブが趣味なメンバーがいるグループは?」「グループ1とグループ3」のような感じです。 一応自分で考えてみたのが、以下ですが、これだと趣味の指定が増減すると大きくSQLが変わってしまいます。 もっといいやり方はないでしょうか? 私はPostgreSQL8を使ってますが、汎用的なSQLであれば、そっちの方がいいです。 SELECT distinct m.g_id FROM members m join hobbies h ON m.h_id = h.h_id where h.h_name = 'drive' INTERSECT SELECT distinct m.g_id FROM members m join hobbies h ON m.h_id = h.h_id where h.h_name = 'book';
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- root139
- ベストアンサー率60% (488/809)
No.1です。No.2さんの回答をちょっと変えれば、HAVING句とCASE式の組み合わせでもいけることに気が付きました。 例) --------------------------------------------------------------- SELECT DISTINCT g_id FROM members m JOIN hobbies h USING(h_id) GROUP BY g_id HAVING SUM(CASE WHEN h_name = 'drive' THEN 1 ELSE 0 END) > 0 AND SUM(CASE WHEN h_name = 'book' THEN 1 ELSE 0 END) > 0 ; -------------------------------------------------------------------
- jamshid6
- ベストアンサー率88% (591/669)
あと考えられるのは、以下のような方法です。 SELECT m.g_id FROM members m INNER JOIN groups g ON g.g_id=m.g_id INNER JOIN hobbies h ON h.h_id=m.h_id WHERE h_name IN ('book','drive') GROUP BY m.g_id HAVING COUNT(DISTINCT h_name)=2
- root139
- ベストアンサー率60% (488/809)
思いつくのは、下記の2つですね。どちらもあまりスッキリはしませんが。 ・指定する趣味の数だけ自己結合を行う。 例) --------------------------------------------------------------- SELECT DISTINCT m1.g_id FROM members m1 JOIN hobbies h1 ON m1.h_id = h1.h_id JOIN members m2 ON m1.g_id = m2.g_id JOIN hobbies h2 ON m2.h_id = h2.h_id WHERE h1.h_name = 'drive' AND h2.h_name = 'book' ; ------------------------------------------------------------------- ・指定する趣味の数だけEXISTSで条件を書く。 例) --------------------------------------------------------------- SELECT g_id FROM groups g WHERE EXISTS (SELECT * FROM members JOIN hobbies USING (h_id) WHERE g_id = g.g_id AND h_name = 'drive') AND EXISTS (SELECT * FROM members JOIN hobbies USING (h_id) WHERE g_id = g.g_id AND h_name = 'book') ; -------------------------------------------------------------------
お礼
なるほど。相関サブクエリーを使うんですね。思いつきませんでした。有り難うございました。
お礼
お礼が遅くなりました。これだと、検索条件をINの中にまとめられるので、SQLの見た目が大きく変わらず、非常にいいですね。 GROUP BYした後にh_nameに注目をするというのは思いつきませんでした。 大変参考になりました。有り難うございました。