Laravel whereHas关联表多属性值同时匹配查询问题
问题根因
你当前多属性筛选返回空结果的核心原因是:在同一个whereHas闭包内连续对value_name做等值where判断,生成的SQL逻辑是要求单条attributes记录的value_name字段同时等于China和Grey,但单条属性记录仅会存储一个属性值,永远无法满足该条件,自然返回空结果。
从你给出的表数据可以看到,China、Grey是item_id=1的商品对应的两条独立属性记录,要匹配同时持有多个属性的商品,核心逻辑是统计商品关联的属性中命中所有目标值的记录数,等于传入的筛选属性总数量。
可直接复用的实现代码
该方案支持动态传入任意数量的属性筛选值,兼容单属性、多属性筛选场景:
// 动态传入的待筛选属性值数组,示例为['China', 'Grey'],可根据接口入参动态赋值 $targetAttributeValues = ['China', 'Grey']; $products = Product::where('price', '>', 0) ->orderBy('price', 'asc') ->with('attributes') ->whereHas('attributes', function (Builder $query) use ($targetAttributeValues) { $query->whereIn('value_name', $targetAttributeValues) ->groupBy('item_id') // item_id为attributes表关联products表的外键,可根据实际表字段名调整 ->havingRaw('COUNT(DISTINCT value_name) = ?', [count($targetAttributeValues)]); }) ->get();
逻辑说明
- 先通过
whereIn筛出所有匹配任意一个目标属性值的关联记录 - 按关联的商品ID分组,统计每个商品命中的不同属性值数量
- 仅当命中数量等于传入的筛选属性总数时,判定该商品满足「同时持有所有指定属性」的要求
- 单属性筛选时传入长度为1的数组即可兼容原有逻辑,不需要额外写判断分支
提示:如果你的attributes表不存在同一商品重复存储相同value_name的情况,可以去掉
DISTINCT直接用COUNT(*)统计,查询性能会更好。
内容的提问来源于stack exchange,提问作者Александр Инженер
相关产品推荐
相关产品推荐

