2013-05-09 7 views
5

普通の古いSQLクエリ(ほとんどの場合、ORMを使用するという欠点)にはいくつか問題があります。SQLを使用して2つの条件を持つすべての行を検索する(別のテーブル)

私はPRODUCTSRULESの2つのテーブルを持っています。テーブルRULESには、製品のルールが定義されています。私が望むのは、ルールを定義したすべての製品を取得するためのクエリを書くことです。あなたはSectorIDを使用して、よりその1つの製品に対してRULEを指定することができます

  • ProductIDSectorIDはNULLで、ProductIDが値を持っている)あなたは1つの製品だけのためRULEを指定することができます

    1. ルールは2つの方法で定義されていますはNULLです)

    結果には、ルール(product.ID - rule.ProductID)を持つすべての製品が必要ですが、arルールテーブル(product.SectorID - rule.SectorID)にあるセクタで定義されます。

    PRODUCTS

    ID SectorID 
    1 1 
    2 1 
    3 1 
    4 2 
    5 3 
    6 3 
    

    RULES

    また、結果は、重複した製品(RULESまたはSectorIDによってproductIdによって定義されている製品)

    例を持つことはできません

    ID ProductID SectorID 
    1 1   NULL 
    4 NULL  1 
    5 6   NULL 
    

    期待される結果

    PRODUCTS with IDs : 1, 2, 3, 6 
    
  • 答えて

    4

    私が考えることができる最も簡単な方法ですが、必ずしも最速ではありません。

    SELECT * FROM products AS p WHERE 
         EXISTS (SELECT * FROM rules AS r WHERE p.ID = r.ProductID OR p.SectorID = r.SectorID) 
    
    +1

    これはおそらく最も速いでしょう(関連するインデックスが与えられています)。 ORを2つの独立したEXISTSレッグに分割すると、物事が改善されます: 'WHERE EXISTS(... where p.ID = r.ProductID)またはEXISTS(... WHERE p.SectorID = r.SectorID)' – wildplasser

    +0

    @wildplasser下の結合と同じ計画で、[クエリは、とにかく結合として書き直されます](http://sqlfiddle.com/#!6/7c91c/2)と言います。 –

    2

    両方のクエリを実行し、結果を組み合わせる:

    SELECT ProductID FROM Rules 
    WHERE ProductID IS NOT NULL 
    UNION 
    SELECT p.ID FROM Product p 
    INNER JOIN Rules r ON p.SectorID = r.SectorID 
    

    UNIONは重複IDを除外します。あなたの例が単純化されていると仮定すると、これをサブクエリとして使用してルールを持つすべての製品のリストを取得し、それを使用して他のテーブルと結合して必要なデータを返すことができます。

    別のアプローチ:

    SELECT DISTINCT p.ID FROM Product p 
    INNER JOIN Rules r 
    ON p.ID = r.ProductID OR p.SectorID = r.SectorID 
    

    これらはしてもしなくてもよい異なる実行計画を生成してもよいです。確認し、より速いものを選択する必要があります。

    +1

    あなたの最初のクエリで必要とされていない製品のテーブルに参加します。 'r.productID'を返すだけです。結合を保存することは常に良いことです;-) –

    +1

    そして代理は重複します – cmd

    +0

    @cmd、Declan_K確かに;ありがとう。 –

    1
    select distinct 
         ProductID 
    from rules 
    where ProductID is not null 
    union 
    select distinct 
         p.id 
    from PRODUCTS p 
    inner join 
         RULES r 
    on  r.sectorid = p.sectorid 
    

    ここでは簡単JOINだ、マッチング製品の完全な製品の行を取得するにはSQL Fiddle

    +1

    別称の使用は不要です。組合の後半は重複を返さない。最初の可能性がありますが、後半に重複値が表示されない場合でも、組合はそれらをフィルタリングします。 –

    +0

    良い点。 また、私はヨアキムの答えが私より優れていると思います。 –

    3

    です。 DISTINCTは、商品が商品ルールとセクタールールの両方に一致する可能性があり、一度のみ表示されるようにするために必要です。

    SELECT DISTINCT p.* 
    FROM products p 
    JOIN rules r 
        ON p.ID  = r.ProductID 
        OR p.SectorID = r.SectorID 
    

    An SQLfiddle to test with

    0

    は、私はこのような何かが動作するはずと信じて:

    SELECT DISTINCT p.id 
    FROM Products p 
    LEFT JOIN Rules r1 ON p.id = r1.productID 
    LEFT JOIN Rules r2 ON p.SectorID = r2.SectorID 
    WHERE r1.id IS NOT NULL OR r2.SectorID IS NOT NULL 
    ORDER BY p.id; 
    

    SQL Fiddle

    関連する問題