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

Laravel中GroupBy与orderBy联用失效问题排查

问题分析与解决方案

错误原因

你遇到的问题是SQL执行顺序导致的:GROUP BY的执行优先级高于ORDER BY。你先写的orderBy('scadenza','DESC')只会对最终分组后的结果排序,无法影响分组时选取的行——数据库会默认选取每组中最早匹配到的记录(通常是主键最小的那条),而非排序后的最新记录。

而用->get()->unique()是先把所有数据拉到内存再去重,数据量大时必然会有性能问题,因为要处理的数据集太大。

正确实现思路

要实现“按指定字段分组,取每组最新文档”,需要先通过子查询获取每个分组下最新记录的主键,再关联原查询筛选出这些主键对应的完整数据。这样所有逻辑都在数据库层面完成,性能远高于内存去重。

修改后的代码示例

针对你的完整查询,调整如下:

// 第一步:子查询获取每个分组下最新记录的allegati_files.id
$latestAttachments = Allegato::selectRaw('MAX(allegati_files.id) as attachment_id, gruppo_cors, id_tipologia_grouped')
    ->join('allegati_tipologie_new','allegati_tipologie_new.id_allegato','allegati_files.allegato_id')
    ->join('elenco_allegati_tipologie','elenco_allegati_tipologie.id_auto','allegati_tipologie_new.id_tipologia')
    ->join('elenco_allegati_categorie',function($j) use($allowed_cats){
        $j->on('elenco_allegati_categorie.id_auto','elenco_allegati_tipologie.id_categoria');
        $j->whereIn('elenco_allegati_categorie.id_auto',$allowed_cats);
    })
    ->leftjoin('tsys_corsi','tsys_corsi.id_auto','allegati_files.tipo')
    ->leftjoin('elenco_allegati_tipologie as elenco_allegati_tipologie2',function($j){
        $j->on('elenco_allegati_tipologie2.id_auto','allegati_tipologie_new.id_tipologia');
        $j->where('elenco_allegati_tipologie2.group_all',1);
    })
    ->whereIn('allegato_id',$all_attachments_ids)
    ->groupBy('gruppo_cors','id_tipologia_grouped');

// 第二步:关联子查询,只取每个分组的最新记录
$query = Allegato::select('allegati_files.*','allegati_tipologie_new.id_tipologia as id_tipologia',
        'elenco_allegati_tipologie.nome_tipologia','elenco_allegati_tipologie.ordinamento as ordinamento_tipologie',
        'elenco_allegati_tipologie2.id_auto as id_tipologia_grouped',
         'elenco_allegati_categorie.nome_categoria','elenco_allegati_categorie.ordinamento as ordinamento_categoria',
        'elenco_allegati_categorie.shortname_categoria', 'elenco_allegati_categorie.id_auto as id_categoria')
    ->join('allegati_tipologie_new','allegati_tipologie_new.id_allegato','allegati_files.allegato_id')
    ->join('elenco_allegati_tipologie','elenco_allegati_tipologie.id_auto','allegati_tipologie_new.id_tipologia')
    ->join('elenco_allegati_categorie',function($j) use($allowed_cats){
        $j->on('elenco_allegati_categorie.id_auto','elenco_allegati_tipologie.id_categoria');
        $j->whereIn('elenco_allegati_categorie.id_auto',$allowed_cats);
    })
    ->leftjoin('tsys_corsi','tsys_corsi.id_auto','allegati_files.tipo')
    ->leftjoin('elenco_allegati_tipologie as elenco_allegati_tipologie2',function($j){
        $j->on('elenco_allegati_tipologie2.id_auto','allegati_tipologie_new.id_tipologia');
        $j->where('elenco_allegati_tipologie2.group_all',1);
    })
    ->whereIn('allegato_id',$all_attachments_ids)
    // 关联子查询,筛选出每个分组的最新记录ID
    ->joinSub($latestAttachments, 'latest', function($join) {
        $join->on('allegati_files.id', '=', 'latest.attachment_id')
             ->on('gruppo_cors', '=', 'latest.gruppo_cors')
             ->on('id_tipologia_grouped', '=', 'latest.id_tipologia_grouped');
    })
    ->orderBy('scadenza','DESC');

说明

  • 子查询按gruppo_cors和id_tipologia_grouped分组,通过MAX(allegati_files.id)获取每组中最新记录的主键(假设scadenza最新的记录主键也最大;如果scadenza可能重复,建议用MAX(scadenza)结合主键来确保唯一性)。
  • 主查询通过joinSub关联子查询,只保留子查询中获取到的最新记录,最后再按scadenza排序即可。
  • 这种方式将所有筛选逻辑放在数据库层面执行,避免了内存中处理大量数据,性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:52:50