You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent按slug分组:优先选取非空client_id记录

Laravel Eloquent 按Slug分组优先选取Client_id非空记录的实现

针对你的需求——按slug分组时优先保留client_id非空的记录,无符合条件的记录则保留client_id为null的记录,你当前的代码存在两个核心问题:

  1. groupBy包含了id、name等唯一/非分组字段,导致每个记录都会被单独分组,完全起不到按slug去重的作用;
  2. latest()未指定排序优先级,无法实现优先选取client_id非空记录的逻辑。

下面提供两种可靠的实现方案:

方案一:利用排序+分组(适用于MySQL关闭ONLY_FULL_GROUP_BY或兼容模式)

通过排序让client_id非空的记录排在每组最前面,再按slug分组取每组第一条:

Field::select('slug', 'id', 'name', 'field_type')
    ->where(function($q) use($clientModel) {
        $q->whereNull('client_id')->orWhere('client_id', $clientModel->id);
    })
    ->orderByRaw('client_id IS NULL, id DESC') // 先把client_id非空的排到前面,再按id倒序
    ->groupBy('slug')
    ->paginate(20);

注:如果你的MySQL开启了ONLY_FULL_GROUP_BY模式,这种写法会触发SQL报错,建议使用方案二。

方案二:窗口函数实现(推荐,MySQL 8.0+)

使用ROW_NUMBER()窗口函数给每个slug分组的记录编号,让client_id非空的记录编号为1,最后筛选编号为1的记录:

Field::select('slug', 'id', 'name', 'field_type')
    ->from(function($query) use($clientModel) {
        $query->select('*', 
            \DB::raw('ROW_NUMBER() OVER (PARTITION BY slug ORDER BY client_id IS NULL ASC) as rn')
        )->where(function($q) use($clientModel) {
            $q->whereNull('client_id')->orWhere('client_id', $clientModel->id);
        });
    }, 'sub')
    ->where('rn', 1)
    ->paginate(20);

逻辑说明:

  • PARTITION BY slug按slug对记录分组;
  • ORDER BY client_id IS NULL ASC中,client_id IS NULL对非空记录返回0,空记录返回1,升序排序后非空记录会排在每组的最前面,编号为1;
  • 最终筛选rn=1的记录,就实现了优先取client_id非空、无则取空的需求。

内容的提问来源于stack exchange,提问作者Vinod Patidar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:03:11