2009-04-01 18 views
2

必要なすべてのプロパティに一致する特定の属性が結合テーブルに格納されている製品をフィルタリングする必要があります。つまり、要件を追加して検索範囲を絞り込んでください。1つの列でグループ化された行を別の列に必要な値でグループ化する方法

問題は、実際には製品特性の次(簡体字)表を与えられ、参加するのではなく、私は思うのプロパティテーブルに関する:

 
id product_id property value 
--------------------------------- 
1 1   color  red 
2 1   size  small 
3 2   color  red 
4 2   size  large 

は、どのように私は 'の値が両方あるすべてproduct_idsになるだろう赤 "と"小 "?

似たような質問was asked非常に完全に答えられていません。解決策は、COUNTおよびHAVINGを含み、必要な値と同じ数の行が各グループに存在する行を取得します。

SELECT product_id, count(*) AS group_count FROM properties where 
value = 'red' OR value = 'small' 
GROUP BY product_id 
HAVING group_count = 2 

これは機能しますが、パフォーマンスについて心配です。より良い方法があるようです。

結局、これはと結合する必要があるであろう、あるいは少なくともproductsテーブルをフィルタリングするために使用:

 
id name  
------------- 
1 Product 1 
2 Product 2 

私は、私はフィルタリングする必要がある製品にこれらのプロパティテーブルの2に参加していることを言及するのを忘れてしまいました1つは製品の通常の属性、もう1つは利用可能な設定可能なオプション(バリエーションのようなビット)です。 ユーザーが次のような製品をフィルタできるようにすることです: "gender = '男性'、brand = 'nike'、およびサイズ== 'small'のジェンダーとブランドが 'プロパティ'で、サイズがオプションである

カウントを持つグループを使用するソリューションは、まだ結合された2つのテーブルで動作しますが、面倒ですが、必要なグループ数は、最初のテーブルの必要なオプションの数に、二番目。

プロパティ(および他のテーブル)からIDを取り出して、次に選択するだけです.ID IN(ids)は、両方のプロパティテーブルのIDのセットと一致していますが、私はこれを行うアイデアが気に入らないしかし本当に長いidsのリストを持っています。

+0

例でgroup_countが2より大きい場合はどうなりますか?彼らは除外されます。私はあなたがそれを持つ必要があると思うgroup_count> 0 – Eppz

答えて

2

ない、これは高速ですが、あなたのフィルタの条件から生成されたサブクエリから合流がうまくいくことを確認:

Select p.name, p.id from product p, 
(select product_id from properties where value='red') colors, 
(select product_id from properties where value='small') sizes 
where p.id=colors.product_id and p.id=sizes.product_id 
+0

ありがとう、これは動作します。私はパフォーマンスを比較します。物事をより複雑にするために、同じ方法で結合してフィルタリングする別のプロパティタイプテーブルがありますが、このアプローチでは別のテーブルを組み込むのは簡単です。 – DavidNorth

2
SELECT DISTINCT p1.product_id, pn.name 
FROM properties p1, properties p2, 
    productNames pn 
WHERE p1.product_id = p2.product_id 
AND p1.property = 'size' and value = 'small' 
AND p2.property = 'color' and value = 'red' 
AND pn.id = p1.product_id 
+0

ありがとう、これは動作しますが、2回以上テーブルに参加する必要がある場合、どのようにパフォーマンスが向上するか心配です。 – DavidNorth

+0

これは他のソリューション、特にサブクエリのアプローチと同様に機能します。自分自身にテーブルを参加させること自体は、パフォーマンスのキラーではありません。 – JohnFx

+0

DISTINCT p1.product_id、プロパティP1からpn.product 、プロパティP2を選択 製品PN WHERE p1.product_id = p2.product_id AND p1.property = 'サイズ' とp1.value = '小さな' およびP2 .property = 'color'とp2.value = 'red' AND pn.id = p1.product_id このクエリをテストしました。それは十分に速くなります。 –

1

あなたが自分自身にテーブルを結合することができます:

SELECT 
prop1.product_id 
FROM 
properties prop1 
JOIN properties prop2 
    ON prop1.product_id = prop2.product_id 
WHERE 
prop1.property = 'color' and prop1.value = 'red' 
and prop2.property = 'size' and prop2.value = 'small' 
1

さらに別の出会い属性値データモデルの落とし穴の1つと関連しています。

「色」が「赤」に一致し、「サイズ」が「小さい」と一致する製品(実際にはプロパティが重要であるという質問はしません)を想定すると、あなたはどのように必要な試合のリストを代表していますか?それらは、一時テーブルに格納された区切られた文字列として渡されますか、SQLは動的に構築されますか?

テーブルに(一時的にまたは他の方法で)取得できる場合は、次のクエリが機能するはずです。サブクエリのために、パフォーマンスは、使用しているデータの量とそのインデックス方法に非常に依存します。また、同じ製品のテーブルに重複したプロパティがあると、物事が捨てられる可能性があるので、そのことを考慮する必要があります。

SELECT 
    P.* 
FROM 
    Products P 
WHERE 
    NOT EXISTS 
    (
     SELECT 
      * 
     FROM 
      Product_Search_Template PST 
     LEFT OUTER JOIN Properties P2 ON 
      P2.property = PST.property AND 
      P2.value = PST.value AND 
      P2.product_id = P.product_id 
     WHERE 
      P2.id IS NULL 
    ) 

SELECT 
    P.* 
FROM 
(
    SELECT 
     PROP1.product_id, 
     COUNT(*) AS match_count 
    FROM 
     Properties PROP1 
    INNER JOIN Product_Search_Template PST ON 
     PST.property = PROP1.property AND 
     PST.value = PROP1.value 
    GROUP BY 
     PROP1.product_id 
) SQ 
INNER JOIN Products P ON 
    P.product_id = SQ.product_id 
WHERE 
    SQ.match_count = (SELECT COUNT(*) FROM Product_Search_Template) 
+0

プロパティ名は重要ではなく、ただの値です。実際の表では、名前と値の両方が外部キーです。 私は動的にSQLを構築するでしょう、必要な値は配列から来ています。私は最終的に同じクエリ内の別のプロパティタイプテーブルをフィルタリングする必要があります。 – DavidNorth

+0

だから、「小さい」または「流通範囲」の「大きさ」(単にこれを作っている)が「小さい」という「小」の検索では、同じ?それは私がコーディングしたものではありません。私が実際のキーボードに乗るとき、私はそれをきれいにするでしょう。 –

関連する問題