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

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

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

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

2回答

10881閲覧

中間テーブルからの検索方法

urdapple

総合スコア83

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

1クリップ

投稿2015/08/04 04:08

編集2015/08/04 04:10

料理テーブル(A)と材料テーブル(B)があったとして、その料理に使う材料の関係性をつなぐ中間テーブル(C)があったとします。(いわゆるhasAndBelongsToManyな関係のテーブルです)
材料として、りんご、はちみつを検索し、料理テーブルからカレーとアップルパイを引っ張りだすSQL文が浮かびません。
材料が少なければサブクエリを繋いで探す方法はなんとなーく浮かんだんですけれど、材料が増えてくるとその分だけサブクエリも増え、著しくレスポンスが悪くなる気がします。

なるべくレスポンスを悪くせずに検索する方法はありますでしょうか?

Aのカラム(他にもカラムはある、値段等々)
idとcook(料理名)
1,カレー
2,生姜焼き
3,プリン
4,アップルパイ

Bのカラム
idとmaterial(素材名)
1,リンゴ
2,豚肉
3,ハチミツ
4,牛乳
5,砂糖
6,塩

Cのカラム
idとAid、Bid
1,1,1
2,1,3
3,1,4
4,2,2
5,2,6
6,3,3
7,3,4
8,3,5
9,4,1
10,4,3
11,4,5

一応どうにか考えたクエリです

sql

1select * 2from A 3join 4(/* 以下のクエリで材料テーブルを横に並べ替えている */ 5 select 6 aid, 7 /* ↓の2行が、検索する材料が増えると増えていく */ 8 case when sum(case when bid = 1 then 1 else null end) = 1 then 1 else 0 end as material_1, 9 case when sum(case when bid = 3 then 1 else null end) = 1 then 1 else 0 end as material_2 10 from C 11 group by aid 12 having material_1 = 1 and material_2 = 1 /* ここも材料分増える */ 13) as B 14on A.id = B.aid

何かあんまりスマートじゃないですよね・・・
中間テーブルが増えたらかなりレスポンスも悪くなるような気もしますし・・・

ちなみにcakephpで開発中なんですけれど、上のSQLを効率よくcakephpのfind文にできるんでしょうか???

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

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

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

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

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

guest

回答2

0

ベストアンサー

一つの料理に対して同じ素材が重複してない前提があるなら(一意性制約とかで)、次のように in で条件の素材を羅列して、having で条件の数を指定する、とかでできないでしょうか。

sql

1select A.id, A.cook from A 2 inner join C on A.id = C.aid 3 inner join B on B.id = C.bid 4where B.id in (1, 3) 5group by A.id, A.cook 6having count(*) = 2

distinct で重複を除外してもいいかもしれません。

sql

1select A.id, A.cook 2from A 3 inner join C on A.id = C.aid 4 inner join B on B.id = C.bid 5where B.id in (1, 3) 6group by A.id, A.cook 7having count(distinct B.id) = 2;

投稿2015/08/04 04:42

編集2015/08/04 04:48
ngyuki

総合スコア4514

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

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

urdapple

2015/08/04 04:52

おおおおおぉおぉ! 素材重複していないです。 なので、これレスポンス良さそうですね? select A.id, A.cook from A inner join C on A.id = C.aid inner join B on B.id = C.bid where B.material in ('リンゴ', 'ハチミツ') /* ここと */ group by A.id, A.cook having count(*) = 2 /* ここを、素材が増える毎に増やせばいいわけですね */ ちょっとやってみます。 ありがとうございましたm(_ _)m
guest

0

回答になっていないかもしれませんが、
料理名素材名に関するデータ数があまり多くないなら、あらかじめ全レコードを読み込んで変数に保持した方が処理速度が向上する場合があります。複雑なSQL文を書く必要もなくなり、結果メンテナンス性が向上します。

投稿2015/08/04 04:13

rik

総合スコア1151

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

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

urdapple

2015/08/04 04:20

実際にはちょっと違う項目名なのですが、それぞれに1000件以上あり、中間テーブルの件数は万単位なんです。 ですので、できればSQLでの処理をしたいんです。 でも提案のご提示ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問