2016-02-27 77 views
2

我有一個多對多關係,通過聯結表連接。我的具體情況是食譜和配料。我想選擇所有不包含給定列表中不含成分的食譜。例如,如果我輸入芝士,烤麪包和餅乾,我希望結果包括烤麪包,奶酪和薄脆餅乾,但不包括吐司麪包。MySQL多對多聯結表:從A中選擇所有不包含B中的值的項不在列表中

因此,像:

SELECT * FROM 
recipe 
JOIN recipe_ingredient on recipe.id = recipe_ingredient.recipe_id 
JOIN ingredient on ingredient.id = recipe_ingredient.ingredient_id 
WHERE ingredient.name 
??? 
("cheese", "toast", "crackers") 

選擇其中確實包含任何或所有這些成分是很容易的,但如果能夠避免它,我不希望有隨後篩選出結果的食譜其中包含未列出的成分。

編輯:
一些示例表:實現這個

ingredient 
----------- 
id | name 
1 | "cheese" 
2 | "toast" 
3 | "crackers" 
4 | "jam" 

recipe 
----------- 
id | name 
1 | "cheese on toast" 
2 | "cheese with crackers" 
3 | "jam on toast" 

recipe_ingredient 
------------------------- 
recipe_id | ingredient_id 
1   | 1 
1   | 2 
2   | 1 
2   | 3 
3   | 2 
3   | 4 
+0

你能告訴您三個表的一些樣本數據,好嗎?只需幾行,我們就可以瞭解數據在這些表格上的格式。 –

回答

2

的一種方法是,選擇那些在你的標準未列出的任何成分配方使用ALL使用子查詢匹配:

SELECT r.id 
FROM recipe r 
JOIN recipe_ingredient ri on r.id = ri.recipe_id 
JOIN ingredient i on i.id = ri.ingredient_id 
WHERE i.name <> ALL (SELECT 'cheese' UNION SELECT 'toast' UNION SELECT 'crackers') 
GROUP BY r.id 

要僅檢索符合條件的配方,可以使用非常相似的<> ALL比較來包裝上述語句。

SELECT * 
FROM recipe 
WHERE id <> ALL (
    SELECT r.id 
    FROM recipe r 
    JOIN recipe_ingredient ri on r.id = ri.recipe_id 
    JOIN ingredient i on i.id = ri.ingredient_id 
    WHERE i.name <> ALL (SELECT 'cheese' UNION SELECT 'toast' UNION SELECT 'crackers') 
    GROUP BY r.id 
    ); 

附加說明:其實NOT IN<> ALL一個別名,所以你可以互換使用。

鑑於你的樣品也只會返回:

id | name 
---|------------------------- 
1 | cheese on toast 
2 | cheese with crackers 

看到它在這裏工作:http://sqlfiddle.com/#!9/f20010/25

+0

我比你更喜歡你的答案,它也有更好的執行計劃。它應該是被接受的! +1 :)不知道這種技術 –

+1

@JorgeCampos非常感謝您的友好的話:) –

+1

冒昧添加一個可用的SQLFiddle :) –

0

漂亮的把戲這一個。但這是可以完成的。這裏的技巧部分是知道每個配方有多少配料,然後將其與具有給定參數的配料量進行比較。

select tb.name 
    from (select r.id, r.name, count(*) qtd 
      from ingredient i 
        inner join recipe_ingredient ri 
        on i.id = ri.ingredient_id 
        inner join recipe r 
        on r.id = ri.recipe_id 
      where i.name in ('cheese', 'toast', 'crackers') 
      group by r.id, r.name 
     ) tb 
    where exists (select 1 
        from ingredient i 
         inner join recipe_ingredient ri 
          on i.id = ri.ingredient_id 
         inner join recipe rr 
          on rr.id = ri.recipe_id 
        where rr.id = tb.id 
        group by rr.id 
        having count(*) = tb.qtd) 

首先,我選擇了所有配料,你過濾它從它有多少成分計算的食譜。這第一個查詢會給我:

"cheese on toast"  2 
"cheese with crackers" 2 
"jam on toast"   1 

而且在EXISTS條款我做了一個子查詢來計算所有的食譜有全部成分,並與上子查詢加盟。所以它只會給我列出的那些。

看到它在這裏工作:http://sqlfiddle.com/#!9/f20010/22

相關問題