通过分组和Laravel获取最近的行

mat*_*esj 1 mysql sql laravel eloquent laravel-5

即使有这样的多个问题,我也无法通过分组返回具有最近日期的行.

我有下表..

| message_id | from | to | created_at | status
----------------------------------------------
|    1       |   1  |  2 | 2017-04-06 |   1
|    2       |   1  |  2 | 2017-04-07 |   0
|    3       |   3  |  4 | 2017-04-06 |   1
|    4       |   3  |  4 | 2017-04-07 |   0
----------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我试着获取最近日期的行.

| message_id | from | to | created_at | status
----------------------------------------------
|    2       |   1  |  2 | 2017-04-07 |   0
|    4       |   3  |  4 | 2017-04-07 |   0
Run Code Online (Sandbox Code Playgroud)

目前,此查询返回具有上次最近日期的行.

$messages = Message::where('to', Auth::id())
                    ->groupBy('from')
                    ->orderBy('created_at', 'DESC')
                    ->paginate(10);
Run Code Online (Sandbox Code Playgroud)

Iva*_*ova 6

问题是结果集将首先分组然后排序.您可以使用嵌套选择来获得所需内容.

SQL查询:

SELECT t.* FROM (SELECT * FROM messages ORDER BY created_at DESC) t GROUP BY t.from
Run Code Online (Sandbox Code Playgroud)

与Laravel:

$messages = Message::select(DB::raw('t.*'))
            ->from(DB::raw('(SELECT * FROM messages ORDER BY created_at DESC) t'))
            ->groupBy('t.from')
            ->get();
Run Code Online (Sandbox Code Playgroud)

你只需要添加你的where()条款.

  • 此解决方案违反了 sql 标准,如果仅设置完整的 group by sql 模式(多年来一直是默认设置),则会失败! (3认同)
  • 每次我使用 group by 时,它都会返回最旧的一个,我想要的只是最新的。没有错误。 (2认同)

Aus*_*ful 6

如果有人仍在寻找一个简短而雄辩的答案,groupBy()只需在后面latest()添加 即可...unique()get()

$unreadMessages = Message::where('receiver_id', Auth::user()->id)
    ->where('read_at', null)
    ->latest()
    ->get()
    ->unique('user_id');
Run Code Online (Sandbox Code Playgroud)

- - 更新 - -

上述解决方案的问题在于它unique()在结果集上使用方法,效率不高,因为它在从数据库检索结果集后对整个结果集进行操作。这可能很慢并且占用资源,特别是在处理大型数据集时。

  • 解决方案1

    $unreadMessages = Message::where('receiver_id', Auth::user()->id) ->where('read_at', null) ->latest('created_at') ->groupBy('user_id') ->得到();

在这里,我们使用groupBy()方法而不是unique()在结果集上使用。应用groupBy()在数据库级别,效率会高很多。

  • 解决方案2

    $unreadMessages = Message::select('user_id', DB::raw('max(created_at) as max_created_at'), DB::raw('*')) ->where('receiver_id', Auth::user( )->id) ->where('read_at', null) ->groupBy('user_id') ->get();

在此查询中,我们选择user_id、 、max(created_at) as max_created_at和 ,*这将给出所有列。

通过使用groupBy('user_id')只会选择不同的 user_id,并且使用max(created_at) as max_created_at它将为您提供每个用户的最新消息。这样,您可以通过对数据库的单个查询来检索每个用户的最新未读消息。

  • Unique 是一种集合方法,而不是查询构建器方法。这是非常低效的。 (11认同)

M K*_*aid 5

要获取每个记录的最新记录,from您可以使用自连接

DB::table('message as m')
  ->select('m.*')
  ->leftJoin('message as m1', function ($join) {
        $join->on('m.from', '=', 'm1.from')
             ->whereRaw(DB::raw('m.created_at < m1.created_at'));
   })
  ->whereNull('m1.from')
  ->orderBy('m.created_at', 'DESC')
  ->paginate(10);
Run Code Online (Sandbox Code Playgroud)

在 SQL 中它看起来像

select m.*
from message m
left join message m1 on m.from = m1.from
and m.created_at < m1.created_at
where m1.from is null
order by m.created_at desc
Run Code Online (Sandbox Code Playgroud)

Laravel Eloquent 选择具有 maxcreated_at 的所有行

  • 这是我类似问题的最佳答案。 (3认同)