MySQL多对多连接表:从A中选择所有在B不在列表中不包含值的条目

MySQL多对多连接表:从A中选择所有在B不在列表中不包含值的条目,mysql,Mysql,我有一个多对多关系,通过连接表连接。我的具体案例是食谱和配料。我想选择所有不包含在给定列表中的成分的食谱。例如,如果我输入奶酪、吐司和饼干,我希望结果包括吐司上的奶酪、带饼干的奶酪,但不包括吐司上的果酱 比如: SELECT * FROM recipe JOIN recipe_ingredient on recipe.id = recipe_ingredient.recipe_id JOIN ingredient on ingredient.id = recipe_ingredient.ingr

我有一个多对多关系,通过连接表连接。我的具体案例是食谱和配料。我想选择所有不包含在给定列表中的成分的食谱。例如,如果我输入奶酪、吐司和饼干,我希望结果包括吐司上的奶酪、带饼干的奶酪,但不包括吐司上的果酱

比如:

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

实现这一点的一种方法是选择包含任何未在您的条件中列出的成分的配方,以便与子查询匹配:

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

看到它在这里工作了吗:

这张很漂亮。但这是可以做到的。这里的诀窍是知道每个配方有多少成分,然后将其与给定参数的成分量进行比较

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
子句中,我做了一个子查询,计算所有配方的总成分,并将其与上面的子查询连接起来。所以它只会给我列出的那些


看到它在这里工作了吗:

请您展示一下三个表中的一些示例数据好吗?只需要几行代码,我们就可以了解您的数据在这些表上是如何格式化的。我更喜欢您的答案,它也有更好的执行计划。它应该是被接受的+1:)不知道这个技巧
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