多くのすべての条件を満たすことを要求することで、1 対多のクエリをフィルタリングする

StackOverflow https://stackoverflow.com/questions/481588

  •  20-08-2019
  •  | 
  •  

質問

次の表を想像してください。

テーブルボックスを作成します(id int, name text, ...);

create table thingsinboxes( id int, box_id int, thing enum('apple,'banana','orange');

テーブルは次のようになります。

Boxes:
id | name
1  | orangesOnly
2  | orangesOnly2
3  | orangesBananas
4  | misc

thingsinboxes:
id | box_id | thing
1  |  1     | orange
2  |  1     | orange
3  |  2     | orange
4  |  3     | orange
5  |  3     | banana
6  |  4     | orange
7  |  4     | apple
8  |  4     | banana

少なくとも 1 つのオレンジが含まれ、オレンジ以外は何も含まれていないボックスを選択するにはどうすればよいですか?

数十万の箱、おそらく箱に入ったものが百万個あると仮定すると、これはどのようにスケールされるでしょうか?

可能であれば、結果セットをスクリプトで後処理するのではなく、これをすべて SQL で保持したいと考えています。

私は postgres と mysql の両方を使用しているので、mysql がサブクエリを最適化しないことを考えると (バージョン 6 以前のバージョンでは)、サブクエリはおそらく悪いです。

役に立ちましたか?

解決

SELECT b.*
FROM boxes b JOIN thingsinboxes t ON (b.id = t.box_id)
GROUP BY b.id
HAVING COUNT(DISTINCT t.thing) = 1 AND SUM(t.thing = 'orange') > 0;

GROUP BY を使用しない別の解決策は次のとおりです。

SELECT DISTINCT b.*
FROM boxes b
  JOIN thingsinboxes t1 
    ON (b.id = t1.box_id AND t1.thing = 'orange')
  LEFT OUTER JOIN thingsinboxes t2 
    ON (b.id = t2.box_id AND t2.thing != 'orange')
WHERE t2.box_id IS NULL;

いつものように、クエリのスケーラビリティやパフォーマンスについて結論を下す前に、 試してみる必要があります 現実的なデータセットを使用してパフォーマンスを測定します。

他のヒント

私は箱の比較的小さな割合はオレンジが含まれている場合しかし、あなたはthingフィールドにインデックスを使用して物事をスピードアップすることができるはず、ビルKarwinのクエリがちょうど良いと思います:

SELECT b.*
FROM boxes b JOIN thingsinboxes t1 ON (b.id = t1.box_id)
WHERE t1.thing = 'orange'
AND NOT EXISTS (
    SELECT 1
    FROM thingsinboxes t2
    WHERE t2.box_id = b.id
    AND t2.thing <> 'orange'
)
GROUP BY t1.box_id
それはあまりにも高価ではありませんので、

WHERE NOT EXISTSサブクエリは、多くのオレンジがない提供、一度オレンジ事あたりに実行されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top