2

属しているグループに応じて機能ステートメントが「and」または「or」条件で形成される特定の機能の製品を選択するクエリを作成する方法は?

状況説明

  1. 商品のあるお店があります。
  2. 製品には機能がある場合とない場合があります。
  3. 顧客は製品の特定の機能を探します。これは、フォームに記入して機能 ID の配列を送信することを意味します。
  4. データベースでは、各フィーチャは 1 つのフィーチャ グループにのみ属します。
  5. 最初のグループ (disjunction 属性が true、「OR」と呼ばれる) では、機能の 1 つが顧客から提出された機能と一致する場合に製品を表示できます。
    例: 形状を選択: 円、正方形、三角形 円、正方形、または三角形の製品が表示されます。
  6. 2 番目のグループ (disjunction 属性が false、「AND」と呼ばれる) では、製品が顧客から提出されたすべての機能を備えている場合にのみ製品を表示できます。
    例: 赤、緑、青の色を選択すると、赤と緑と青の製品が表示されます。

テスト環境

http://sqlfiddle.com/#!12/f4db7

"OR" クエリ
機能のない製品を除いて機能します。

SELECT product_id 
FROM product_features 
WHERE product_features.feature_id IN ( 
    SELECT feature_id FROM features 
    LEFT JOIN feature_groups 
        ON features.feature_group_id = feature_groups.feature_group_id 
    WHERE feature_id IN (11, 12, 13) AND feature_groups.disjunction = TRUE 
)
GROUP BY product_id

"AND" クエリ
このクエリは、選言が偽であるフィーチャの数がわからないため使用できません。

SELECT product_id FROM product_features
WHERE feature_id IN (43, 53, 63)
GROUP BY product_id
HAVING COUNT(DISTINCT feature_id) = 3
4

1 に答える 1

1

「または」ケース

よりシンプルで高速:

SELECT DISTINCT pf.product_id 
FROM   product_features    pf
LEFT   JOIN features       f  USING (feature_id)
LEFT   JOIN feature_groups fg USING (feature_group_id)
WHERE (f.feature_id = ANY (_my_arr) 
AND    fg.disjunction)
OR     _my_arr  = '{}';

... どこにまたはが_my_arrできます 。代わりに使用する場合。'{11, 12, 13}'::int[]'{}'::int[]_my_arrNULL_my_arr IS NULL

  • 演算子の優先順位 により、AND前にバインドしOR、括弧は必要ありません。ただし、読みやすさは向上する可能性があります。

  • DISTINCTここはどちらGROUP BYでもいいです。

  • AND fg.disjunction..これはブール型なので、構文を短くすることができます。

  • 一般に、JOIN は別のIN節よりも高速です。

  • USINGは、(便利な!) 命名規則で機能する単なる表記上のショートカットです。

または、さらに高速 (複数の機能の場合) - ケースを簡単に分割できます。

SELECT product_id
FROM   products p
WHERE  EXISTS (
   SELECT 1
   FROM   product_features pf
   JOIN   features         f  USING (feature_id)
   JOIN   feature_groups   fg USING (feature_group_id)
   WHERE  pf.product_id = p.product_id
   AND    f.feature_id = ANY (_my_arr)
   AND    fg.disjunction
   )
OR     _my_arr  = '{}';

入力に応じてアプリのケースを分割したいと思います(機能あり/機能なし)。2 番目のフォームに関係することは些細なことです。

「AND」ケース

これは関係分割の古典的なケースです。この関連する質問の下で、それに対処するためのクエリ手法のすべての武器を集めました:
How to filter SQL results in a has-many-through relationship

になり得る:

SELECT product_id
FROM   product_features p1
JOIN   product_features p2 USING (product_id)
JOIN   product_features p3 USING (product_id)
...
WHERE  p1.feature_id = 43
AND    p2.feature_id = 53
AND    p3.feature_id = 63
...

NOT feature_groups.disjunction質問にもないので、例では無視しています。必要に応じて追加してください。
クエリを作成する前に、有効な feature_id を選択します。

-> SQLfiddle デモ。

于 2013-09-11T16:56:58.890 に答える