2011-06-29 68 views
1

表匹配所有名單:新手問題:N-N加入該

-- products -- 
    id 

-- categories -- 
    id 

-- products_categories -- 
    id 
    product_id 
    category_id 

這可能是一個SQL查詢返回所有產品的ID匹配category_ids的所有給定的名單?

示例:給定列表(3,4,5)我希望所有至少具有AT(可能更多)類別id 3和類別id 4以及類別id 5的product_id?

+0

您需要的關係運算符是[division](http://en.wikipedia.org/wiki/Relational_algebra#Division_2.8.C3.B7.29),俗稱「供應所有部件的供應商」 ](http://www.dbdebunk.com/page/page/772076.htm)。這聽起來像你想[與其餘部分](http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/)和你的情況可能不是一個空分歧。 – onedaywhen

+0

順便提一句SQL對於表中的數據行效果最好,所以如果你的'list'(3,4,5)'被建模爲表中的三行,那麼你的查詢將更容易編寫和泛化。 – onedaywhen

回答

6

用途:

SELECT p.id 
    FROM PRODUCTS p 
    JOIN PRODUCTS_CATEGORIES pc ON pc.product_id = p.id 
    JOIN CATEGORIES c ON c.id = pc.category_id 
    WHERE c.id IN (3,4,5) 
GROUP BY p.id 
    HAVING COUNT(DISTINCT c.id) = 3 

這是俗稱Celko's division

COUNT(DISTINCT c.id)必須等於IN子句中指定的值的數量。否則,重複4/3/5 /等將是誤報。但是,如果確保所有的product_id, category_id對都是唯一的,則可以省略DISTINCT

+0

你可以跳過連接到'PRODUCTS'和'CATEGORIES',因爲他只對ID的 – Magnus

+0

@Magnus感興趣:我同意這個例子,但是IMO簡化了,所以我選擇了最可能的現實世界方法 –

0

,可以理解爲一個雙重否定另一種選擇:

顯示其存在(3,4,5)無類別進行了不匹配與該產品的所有產品。

SELECT p.id 
FROM PRODUCTS p 
WHERE NOT EXISTS 
     (SELECT * 
     FROM CATEGORIES c 
     WHERE c.id IN (3,4,5) 
      AND NOT EXISTS 
       (SELECT * 
       FROM PRODUCTS_CATEGORIES pc 
       WHERE pc.product_id = p.id 
        AND pc.category_id = c.id 
      ) 
    ) 

這就是俗稱的Date's division