多Recipe场景下SQL查询失效:如何筛选用户Pantry含全食材的菜谱
问题分析与解决方案
原SQL语句的核心问题是内层的recipe_ingredient表未与外层recipe表关联,导致查询逻辑变成了“检查所有菜谱的所有食材是否都在用户Pantry中”,而非“检查单个菜谱的所有食材是否都在用户Pantry中”。只要有任意一个菜谱存在用户没有的食材,所有菜谱都会被过滤掉,这就是多菜谱场景下失效的原因。
修正后的NOT EXISTS写法
需要在第二层WHERE中添加关联条件,让recipe_ingredient只针对当前外层的recipe进行检查:
// 改用预处理语句避免SQL注入风险 $stmt = $mysqli->prepare(' SELECT r.* FROM recipe r WHERE NOT EXISTS ( SELECT 1 FROM recipe_ingredient ri WHERE ri.recipe_id = r.id -- 关键:关联当前遍历的菜谱 AND NOT EXISTS ( SELECT 1 FROM pantry p WHERE p.ingredient_id = ri.ingredient_id AND p.iduser = ? ) ) '); $stmt->bind_param('i', $_COOKIE["idUser"]); $stmt->execute(); $res = $stmt->get_result();
另一种直观写法:分组统计验证
通过统计菜谱的总食材数,以及用户Pantry中匹配的食材数,当两者相等时,说明该菜谱的所有食材都被用户拥有:
$stmt = $mysqli->prepare(' SELECT r.* FROM recipe r JOIN recipe_ingredient ri ON r.id = ri.recipe_id LEFT JOIN pantry p ON ri.ingredient_id = p.ingredient_id AND p.iduser = ? GROUP BY r.id HAVING COUNT(ri.ingredient_id) = COUNT(p.ingredient_id) '); $stmt->bind_param('i', $_COOKIE["idUser"]); $stmt->execute(); $res = $stmt->get_result();
重要提醒
原代码直接拼接$_COOKIE["idUser"]到SQL语句中,存在严重的SQL注入风险,上面的示例都改用了预处理语句绑定参数,这是必须修正的安全问题。
内容的提问来源于stack exchange,提问作者Platt90
相关产品推荐
相关产品推荐

