質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

2回答

2721閲覧

MySQLの「1対多」で、「多」の一つを渡して「1対多の全てに該当するデータ」を取得する書き方

re97

総合スコア208

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2020/06/23 22:33

編集2020/06/23 22:44

下記関係のデータがありますす
・「a 4」 … 「tag 東京」「tag 大阪」
・「a 5」 … 「tag 大阪」「tag 福岡」

3テーブル
・aテーブル … 1    
・tagテーブル … 多 
・a_tagテーブル … 中間 


「a 4」 から、「a 4」「tag 東京」「tag 大阪」を取得する場合は、下記のようなSQLを実行しているのですが、

mysql

1SELECT 2 a.id 3 GROUP_CONCAT(DISTINCT t.tag_id), 4 GROUP_CONCAT(DISTINCT t.tag) 5FROM a 6LEFT JOIN a_tag at ON (a.id = at.a_id) 7LEFT JOIN tag t ON (t.tag_id = at.tag_id) 8WHERE a.id = 4 9GROUP BY a.id

「tag 大阪」から、「a4」「tag 東京」「tag 大阪」と、「a 5」「tag 大阪」「tag 福岡」を取得する場合は、どのようなSQLを書けば良いですか?
「1対多」で、「多」の一つを渡して「1対多の全てに該当するデータ」を「GROUP BY a.id」で取得する方法を知りたいです。


試してみたこと
WHERE at.tag_id = 大阪 を追加してみたのですが、タグが1つしか取得できませんでした。
※aのid に対してtag が複数存在する場合でも、「tag 大阪」しか取得されない

1対多の場合、WHERE条件はFROM句に対してしか使用不可ですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/06/23 22:42

取得条件がわかりません(なぜ「a 5」「tag 大阪」「tag 福岡」が取れるのでしょうか)。
re97

2020/06/23 22:44

取得条件を修正しました。
guest

回答2

0

ベストアンサー

aテーブルとtagテーブルは、「多:多」です。
そこに「1:多」の関係を持ち込んでいるのが、a_tagテーブル という中間テーブルです。

こういった、中間テーブルを介した情報取得の場合に駆動表とするのは中間テーブルです。

質問のSQLの情報のみなら、a_tagテーブル とtagテーブルのみで取得できます。

SQL

1SELECT at.a_id 2 , GROUP_CONCAT(DISTINCT t.tag_id) 3 , GROUP_CONCAT(DISTINCT t.tag) 4FROM a_tag at 5 inner join tag t 6 ON t.tag_id = at.tag_id 7WHERE at.a_id = 4 8GROUP BY at.a_id

ただ、データ上GROUP_CONCAT()でDistinctが必要な状況ならDistinctが不要になるようにしておいた方が良いと思われます。

質問にある、「tag='大阪'」を含むデータの抽出は以下です。

SQL

1SELECT at.a_id 2 , GROUP_CONCAT(DISTINCT t.tag_id) 3 , GROUP_CONCAT(DISTINCT t.tag) 4FROM a_tag at 5 inner join tag t 6 ON t.tag_id = at.tag_id 7WHERE at.a_id in (select a_id from a_tag where tag = '大阪') 8GROUP BY at.a_id

または

SQL

1SELECT at.a_id 2 , GROUP_CONCAT(DISTINCT t.tag_id) 3 , GROUP_CONCAT(DISTINCT t.tag) 4FROM a_tag at 5 inner join tag t 6 ON t.tag_id = at.tag_id 7WHERE exists (select 1 from a_tag where tag = '大阪' and a_id = at.a_id) 8GROUP BY at.a_id

投稿2020/06/24 02:36

編集2020/06/24 02:47
sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2020/06/24 10:35

回答ありがとうございます。 タグを条件指定してSELECTしているのに「FROM a」としていた点が間違っていることに気が付きました。 また、タグが含まれているデータを取得したいのに「WHERE a.id = 4」としている条件指定自体も間違っていることにも気が付きました。 「inner join」についてはこれまで一度も使用したことがなくどういう時に使用するのか理解していないため、これから調べてみたいと思います。 最初のSQL「WHERE at.a_id in (select a_id from a_tag where tag = '大阪')」は「大阪タグのidが含まれいれば」という条件指定だと思うので、何となく分かるのですが、 次のSQL「WHERE exists (select 1 from a_tag where tag = '大阪' and a_id = at.a_id)」も、上記と同義ですか?「大阪タグのid」が存在していれば、という感じですか?
sazi

2020/06/24 12:15 編集

両方とも同じ結果になりますが、SQLの動作が異なります。 後者は相関副問合せとよばれ、FROM句で指定している集合の1件毎に問い合わせが行われます。 existsは1件でも条件に合致していればそこで副問合せは終了する動作です。 データの分布に応じてコストが違ってくるので、性能面で使い分けを行います。
re97

2020/06/24 22:48

再度の回答ありがとうございました。 >両方とも同じ結果になりますが、SQLの動作が異なります ・なるほど、この説明は分かりやすかったです >データの分布に応じてコストが違ってくるので、性能面で使い分けを行います ・ INとEXISTSについて検索してみたら、比較ページが色々見つかりました ・大変参考になりました
guest

0

WHERE at.tag_id = 東京 を追加してみたのですが、タグが1つしか取得できませんでした。

※aのid に対してtag が複数存在する場合でも、「tag 東京」しか取得されない

どんなデータがあるのか、テーブルの定義をCREATE TABLE, PRIMARY KEYの情報やテーブル中のデータも INSERTで、現行のSELECT結果と希望する結果もMarkdownの [コード] で質問にできた方が適切なコメントが付き易いです。

ネーミングのセンスの問題だけど、テーブル名の a, a_tag, tag ってもう少しテーブルの内容を想像できるものに変えられることができた方が良いです。

投稿2020/06/23 22:54

Orlofsky

総合スコア16417

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問