如何使用Eloquent和MySQL按最后一个ID排序分组结果?

Jos*_*sen 2 php mysql sql-order-by laravel eloquent

我试过这个查询,但它只订购id列,休息不是.

$chapters = Test::select(DB::raw('*, max(id) as id'))
        ->groupBy('id_equip')
        ->orderBy('id', 'asc')
        ->get();
Run Code Online (Sandbox Code Playgroud)

Jar*_*zyk 7

MySQL中使用时group by你不能依赖order by子句(它不会像你期望的那样工作,即它不会按组排序结果,而是从组中返回随机行).

所以为了达到你想要的,你需要一个subqueryjoin:

// assuming tests table, group by id_equip, order by id
SELECT * FROM tests WHERE id = (
   SELECT MAX(id) FROM tests as t WHERE t.id_equip = tests.id_equip
) ORDER BY id

SELECT * FROM tests 
   JOIN (SELECT MAX(id) as id FROM tests ORDER BY id DESC) as sub
      ON sub.id = tests.id
Run Code Online (Sandbox Code Playgroud)

这将获得id每个最高的id_equip并返回每个的整行.


现在,如果您希望它看起来更直观,我建议采用第一种方法:

Test::where('id', function ($sub) {
   // subquery
   $sub->selectRaw('max(id)')
       ->from('tests as t')
       ->where('t.id_equip', DB::raw('tests.id_equip'));
// order by
})->orderBy('id', 'desc')->get();
Run Code Online (Sandbox Code Playgroud)

但是如果你有大表扫描(就性能而言),第二种方法可能就是这样:

Test::join( DB::raw(
    '(select max(id) as id from tests group by id_equip order by id desc) sub'
  ), 'sub.id', '=', 'posts.id')
  ->get(['tests.*']);
Run Code Online (Sandbox Code Playgroud)

在这里,您需要order by在raw join语句中设置子句.

如果您愿意,还可以使用构建器构建连接子查询:

$sub = Test::selectRaw('max(id)')
        ->groupBy('id_equip')
        ->orderBy('id', 'desc')
        ->toSql();

Test::join( DB::raw(
    "({$sub}) as sub"
  ), 'sub.id', '=', 'posts.id')
  ->get(['tests.*']);
Run Code Online (Sandbox Code Playgroud)