MySQL WHERE不等于条件失效:查询不含指定食材的菜谱失败
解决多对多关系中查询不包含特定食材的菜谱问题
嗨,我来帮你捋清楚这个问题!你当前的查询之所以会返回所有菜谱,核心原因是:当一个菜谱包含多种食材时,只要其中有一个食材ID不是307,这条关联记录就会被保留下来,最后GROUP BY之后还是会把这个菜谱纳入结果——哪怕它其实包含了ID为307的食材。
举个例子:假设某个菜谱同时有食材307和308,你的查询会过滤掉食材307的那条关联记录,但食材308的记录还在,GROUP BY之后这个菜谱依然会出现在结果里,这显然不是你想要的。
下面给你几种靠谱的解决方案:
方案1:使用NOT EXISTS(推荐,性能友好)
这种方式直接检查菜谱是否不存在关联的目标食材,逻辑清晰,数据库也能高效利用索引:
SELECT * FROM recipes r WHERE NOT EXISTS ( SELECT 1 FROM recipe_ingredients ri WHERE ri.fk_Recipe = r.id AND ri.fk_Ingredient = 307 );
方案2:使用LEFT JOIN + IS NULL
通过左连接关联目标食材的记录,然后筛选出没有匹配到的菜谱:
SELECT r.* FROM recipes r LEFT JOIN recipe_ingredients ri ON r.id = ri.fk_Recipe AND ri.fk_Ingredient = 307 WHERE ri.fk_Recipe IS NULL;
这里的关键是把ri.fk_Ingredient = 307写在JOIN条件里,而不是WHERE里,这样才能保留所有菜谱,再过滤掉有匹配的记录。
方案3:使用GROUP BY + HAVING统计
通过分组统计每个菜谱包含目标食材的次数,筛选出次数为0的菜谱:
SELECT r.* FROM recipes r JOIN recipe_ingredients ri ON r.id = ri.fk_Recipe GROUP BY r.id, r.url -- 注意:需要包含recipes表所有非聚合字段,具体取决于你的SQL模式 HAVING SUM(CASE WHEN ri.fk_Ingredient = 307 THEN 1 ELSE 0 END) = 0;
这三种方法都能精准筛选出完全不包含ID为307的食材的菜谱,你可以根据自己的数据库环境选择最顺手的一种~
内容的提问来源于stack exchange,提问作者AirwaveQ
相关产品推荐
相关产品推荐

