You need to enable JavaScript to run this app. Laravel Eloquent 按商品分组查询:取订单数最高商品的最低价格记录
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent 按商品分组查询:取订单数最高商品的最低价格记录

问题原因
  • 原代码写groupBy('product_id')的时候,没有给分组内的字段设定取数规则,MySQL默认会捞每个分组里物理存储最靠前的那条记录返回,所以你拿到的是product_id=1下id=1、售价2.99的记录,不是你要的售价1.99的那条。
  • 当前的排序顺序不对:直接把订单数排序放在分组前面,没有约束同商品下取价格最低记录的规则,和实际需求不匹配。
调整写法

整个查询的执行逻辑要顺着顺序走:先给同一个product_id下的所有记录按价格从低到高排 → 再按product_id做分组截取(这时候数据库每个分组捞的第一条,就是该商品下价格最低的那条) → 最后对每个商品分组的订单总数做倒序排 → 取排名第一的分组就行。
兼容常规MySQL版本的代码如下:

Items::query()
    ->withCount(['orders' => function($q){
        // 保留你原来的订单状态过滤逻辑
        $q->active();
    }])
    // 关键:分组前先按价格升序,让同product_id下价格最低的记录排在组内最前面
    ->orderBy('price', 'asc')
    ->groupBy('product_id')
    // 分组完成后,再按关联订单数倒序,找到订单数最高的商品
    ->orderBy('orders_count', 'desc')
    ->limit(1)
    ->get();
踩坑提醒
  • 如果你的MySQL开了ONLY_FULL_GROUP_BY严格模式,直接跑上面的写法会报未聚合字段的错误,这时候要把withCount的关联统计换成等价的子查询写法,保证SELECT的所有字段都符合分组规则:
Items::query()
    ->select('id', 'product_id', 'price',
        // 这里的过滤条件要和你原来的active()逻辑完全一致
        \DB::raw('(SELECT COUNT(*) FROM orders WHERE orders.product_id = items.product_id AND orders.status = 1) as orders_count')
    )
    ->orderBy('price', 'asc')
    ->groupBy('product_id')
    ->orderBy('orders_count', 'desc')
    ->first();
  • 拿你给出的示例数据校验:product_id=1的有效订单一共3条,比product_id=2的2条多;同product_id=1的记录按价格升序排完,1.99的记录在组内排第一,分组的时候就会捞到这条,完全符合你要的结果。
  • 别把排序顺序搞反:如果把按订单数排序的代码放到分组前面,会导致每个分组里捞到的第一条不是价格最低的,最后返回的结果还是错的。

内容的提问来源于stack exchange,提问作者Mr.SH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 18:15:01