You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

m:n多对多关联表下如何用单条SQL查询匹配全部输入食材的食谱

$recipeFilter = implode(' AND ', $recipeFilters);
...

# 非最优解决方案
我知道可以为每个食材单独查询,再通过数组操作得到想要的结果。
**是否可以用单条SQL实现该需求,具体要怎么写?**
---
### 解决方案
#### 核心思路
现有方案2出错的原因是`AND`要求同一个食材同时匹配所有关键词,不符合业务逻辑。正确逻辑为:先筛选出匹配任意一个搜索关键词的食材关联的食谱,再按食谱ID分组,统计该食谱匹配到的不同食材的数量,数量等于搜索关键词总数时,即说明该食谱覆盖了所有搜索要求。
#### 完整实现代码
```php
// 统计搜索关键词总数
$filterCount = count($filterParams);
// 生成OR匹配条件,这里先对参数做简单转义避免注入,后续建议用预处理方案
$recipeFilters = array_map(function ($param) {
    return "ri.description LIKE '%" . addslashes($param) . "%'";
}, $filterParams);
$recipeFilter = implode(' OR ', $recipeFilters);

$selRecipes = <<<SQL
    SELECT rr.id
    FROM recipe_ingredient ri 
    LEFT JOIN recipe_intermediate_ingredient_recipe riir ON riir.ingredient_id = ri.id 
    LEFT JOIN recipe_recipe rr ON rr.id = riir.recipe_id
    WHERE 
        {$recipeFilter} 
        AND rr.id IS NOT NULL
    GROUP BY rr.id
    -- 匹配到的不同食材数等于输入关键词总数即符合要求
    HAVING COUNT(DISTINCT ri.id) = {$filterCount}
SQL;

$recipes = data_select($selRecipes);
// 直接用array_column替代循环提取id,写法更简洁
$ids = array_column($recipes, 'id');

安全优化建议

现有直接拼接SQL字符串的写法存在SQL注入风险,建议修改为预处理绑定参数的形式:

// 生成带占位符的条件
$recipeFilters = array_fill(0, $filterCount, "ri.description LIKE ?");
$recipeFilter = implode(' OR ', $recipeFilters);
// 生成带前后模糊匹配的绑定参数
$bindParams = array_map(function($param) {
    return "%{$param}%";
}, $filterParams);
// 可修改自定义的data_select函数支持传入绑定参数,通过mysqli_stmt_bind_param完成参数绑定即可

内容的提问来源于stack exchange,提问作者s3c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 10:54:03