Laravel Eloquent同查询中如何让HAVING与WHERE实现OR逻辑?
问题解答
逻辑可行性
你需要的普通字段筛选 OR 聚合字段筛选的逻辑可以实现,但SQL原生不支持直接写WHERE ... OR HAVING ...的语法,两者执行时机不同:WHERE用于过滤聚合前的原始数据行,HAVING用于过滤聚合后的分组结果,需要通过调整查询结构实现,通用实现思路有两种:
- 思路1:将非聚合字段的筛选条件全部挪到HAVING子句中,和聚合字段的筛选条件直接用OR连接。该方案实现简单性能高,适合GROUP BY的字段包含所有非聚合筛选字段的场景(你的示例中GROUP BY id,name、age都属于id对应的唯一属性,符合要求)。
- 思路2:把带聚合的查询封装为子查询,外层查询统一用WHERE判断所有筛选条件,不需要区分聚合/非聚合字段,适用所有场景。
Laravel Eloquent 实现代码
思路1实现(HAVING合并所有条件,优先推荐)
$keyword = '%asdf%'; // 替换为你的实际筛选关键词 $list = YourModel::query() // 替换为你自己的模型类名 ->select('id', 'name', 'age', \DB::raw('SUM(quantity) as sum_quantity')) ->groupBy('id', 'name', 'age') // MySQL严格模式下需要把所有非聚合查询字段放入GROUP BY // 所有筛选条件统一放入HAVING用OR连接 ->having(function ($query) use ($keyword) { $query->where('name', 'like', $keyword) ->orWhere('age', 'like', $keyword) ->orWhere('sum_quantity', 'like', $keyword); }) ->get();
该方案可以在聚合前保留必要的过滤条件提升性能,如果你有不需要OR的全局过滤条件,直接在GROUP BY前加正常WHERE语句即可。
思路2实现(子查询方案,全场景兼容)
如果你的场景不满足非聚合字段可放入HAVING的要求,可以用子查询封装聚合结果后统一筛选:
$keyword = '%asdf%'; // 先构造聚合子查询 $subQuery = YourModel::query() ->select('id', 'name', 'age', \DB::raw('SUM(quantity) as sum_quantity')) ->groupBy('id', 'name', 'age'); // 外层查询统一处理所有OR筛选条件,可直接返回模型实例 $list = YourModel::query() ->fromSub($subQuery, 't') ->where('name', 'like', $keyword) ->orWhere('age', 'like', $keyword) ->orWhere('sum_quantity', 'like', $keyword) ->get();
注意事项
- 若使用MySQL严格模式,GROUP BY子句必须包含所有SELECT中出现的非聚合字段,否则会抛出语法错误。
- 全列筛选扩展时,普通字段直接加OR条件即可,聚合字段在思路1中加HAVING条件、思路2中直接加普通WHERE条件即可。
内容的提问来源于stack exchange,提问作者Sidney Medrano
相关产品推荐
相关产品推荐

