Laravel Eloquent查询如何实现按product_id排序后type按1、2顺序排列
Eloquent 多字段交替排序实现方法
需求说明
需要查询VesselProductDetails表中指定vessel_code的记录,排序规则如下:
- 优先按
product_id字段升序排列 - 同一
product_id分组下,type字段按1、2的顺序交替排列,最终整个结果集呈现1、2、1、2的交替效果
原有查询逻辑:
VesselProductDetails::where('vessel_code',$vessel_code)->orderByDesc('type')->get();
该逻辑仅能实现type倒序排列,无法满足交替排序要求。
实现方案
方案1:SQL窗口函数排序(推荐,性能更优)
支持MySQL 8.0+、PostgreSQL等支持窗口函数的数据库,直接在数据库层完成排序,无需PHP层处理,适合数据量较大的场景:
VesselProductDetails::where('vessel_code', $vessel_code) // 提前过滤非1/2的异常type值,避免排序错乱 ->whereIn('type', [1, 2]) // 给同product_id、同type的记录分配递增行号 ->orderByRaw('ROW_NUMBER() OVER (PARTITION BY product_id, type ORDER BY id) ASC') // 同个行号下先排type=1再排type=2,实现交替 ->orderBy('type', 'ASC') // 最后按product_id升序,满足优先按产品ID排序的要求 ->orderBy('product_id', 'ASC') ->get();
排序逻辑说明:
窗口函数会将相同product_id+type的记录归为同一分区,给分区内的记录按主键顺序生成从1开始的递增序号。先按该序号排序,再按type升序排列,就会依次取出序号1的type=1记录、序号1的type=2记录、序号2的type=1记录、序号2的type=2记录,自然形成1、2交替的效果。
方案2:Laravel集合处理(适合小数据量场景)
如果数据库版本不支持窗口函数,或者数据量较小,可以先查出基础数据,在PHP层通过集合方法完成排序:
VesselProductDetails::where('vessel_code', $vessel_code) ->whereIn('type', [1, 2]) ->orderBy('product_id') ->orderBy('type') ->get() // 先按product_id分组 ->groupBy('product_id') ->map(function ($productGroup) { // 拆分同产品下的type1、type2记录组 $type1List = $productGroup->where('type', 1)->values(); $type2List = $productGroup->where('type', 2)->values(); $sortedGroup = collect(); $maxLength = max($type1List->count(), $type2List->count()); // 按索引交替合并两组数据 for ($i = 0; $i < $maxLength; $i++) { if (isset($type1List[$i])) $sortedGroup->push($type1List[$i]); if (isset($type2List[$i])) $sortedGroup->push($type2List[$i]); } return $sortedGroup; }) // 合并所有产品分组的排序结果 ->collapse() ->values();
内容的提问来源于stack exchange,提问作者Nurideen Yahuza
相关产品推荐
相关产品推荐

