Laravel Eloquent查询作用域:筛选关联表列总和大于父表字段的记录
在Laravel Eloquent中实现关联记录总和大于父表字段的查询作用域
你可以通过数据库层面的聚合过滤逻辑实现需求,避免在集合层面过滤损耗性能,以下是具体方案:
方法一:JOIN + GROUP BY + HAVING
直接关联两张表,通过聚合函数计算关联记录总和,再用havingRaw完成字段比较:
$qualifiedRecords = TableA::select('table_a.*') ->join('table_b', 'table_a.id', '=', 'table_b.table_a_id') ->groupBy('table_a.id') // 按表A主键分组,确保每条父记录只计算一次关联总和 ->havingRaw('SUM(table_b.total) > table_a.total') ->get();
方法二:WHERE EXISTS子查询
如果不想使用JOIN,可通过whereExists子查询检查符合条件的关联记录组,写法更贴合Eloquent关联逻辑:
use Illuminate\Support\Facades\DB; $qualifiedRecords = TableA::whereExists(function ($query) { $query->select(DB::raw('1')) ->from('table_b') ->whereColumn('table_b.table_a_id', 'table_a.id') ->groupBy('table_b.table_a_id') ->havingRaw('SUM(table_b.total) > table_a.total'); })->get();
封装为查询作用域
把逻辑封装到TableA模型的查询作用域中,方便后续复用:
// app/Models/TableA.php use Illuminate\Support\Facades\DB; class TableA extends Model { // 定义关联(若未定义) public function tableBs() { return $this->hasMany(TableB::class); } // 自定义查询作用域 public function scopeWhereRelatedTotalExceeds($query) { return $query->whereExists(function ($subQuery) { $subQuery->select(DB::raw('1')) ->from('table_b') ->whereColumn('table_b.table_a_id', 'table_a.id') ->groupBy('table_b.table_a_id') ->havingRaw('SUM(table_b.total) > table_a.total'); }); } }
使用时直接调用作用域即可:
$qualifiedRecords = TableA::whereRelatedTotalExceeds()->get();
为什么withSum无法直接用于WHERE条件?
withSum是Eloquent在查询完成后,为集合中的模型实例添加的额外属性(比如table_b_total_sum),该属性仅存在于内存中的集合对象里,无法在数据库层面的WHERE条件中使用——我们需要的是在SQL执行阶段完成过滤,因此必须采用上述数据库端聚合方案。
内容的提问来源于stack exchange,提问作者Matdragon
相关产品推荐
相关产品推荐

