Laravel Eloquent groupBy orderBy 在 MariaDB 中给出不同的结果

Posted

技术标签:

【中文标题】Laravel Eloquent groupBy orderBy 在 MariaDB 中给出不同的结果【英文标题】:Laravel Eloquent groupBy orderBy gives different results in MariaDB 【发布时间】:2019-12-01 05:17:55 【问题描述】:

我已经在 SO 和 MariaDB 中阅读过这方面的内容,并且了解 mysql 和 Mariadb 之间的这种不兼容性。但我不确定如何在 Laravel Eloquent / DB 查询中解决这个问题。

我的问题: groupBy orderBy 查询在 MariaDB 和 MySql 中给出了不同的结果。它在 mySql 中运行良好,因为 MariaDB 中的结果顺序不同。

这是我的查询:

$messages = ChatMessages::select(DB::raw('t.*'))
          ->from(DB::raw('(SELECT * FROM chat_messages ORDER BY created_at DESC) t'))
          ->whereIn('message_id', $messageIds)
          ->groupBy('message_id')
          ->orderBy('created_at', 'DESC')
          ->paginate(3);

例如,假设这是chat_messages 表:

+----+----------+---------------------+-----------+
| id | message_id | created_at        | name      |
+----+----------+---------------------+-----------+
| 1  | 1000     | 2017-01-01 06:03:40 | Anna      |
+----+----------+---------------------+-----------+
| 2  | 1007     | 2017-01-02 07:13:20 | Becky     |
+----+----------+---------------------+-----------+
| 3  | 1000     | 2017-01-03 08:20:12 | Christina |
+----+----------+---------------------+-----------+
| 4  | 1004     | 2017-01-03 08:20:15 | Dorothy   |
+----+----------+---------------------+-----------+
| 5  | 1004     | 2017-01-04 09:25:45 | Emma      |
+----+----------+---------------------+-----------+
| 6  | 1000     | 2017-01-05 10:30:10 | Fiona     |
+----+----------+---------------------+-----------+
| 7  | 1007     | 2017-01-05 10:33:23 | Gigi      |
+----+----------+---------------------+-----------+
| 8  | 1007     | 2017-01-06 12:46:34 | Heidi     |
+----+----------+---------------------+-----------+
| 9  | 1000     | 2017-01-06 12:46:34 | Irene     |
+----+----------+---------------------+-----------+
| 10 | 1007     | 2017-01-07 14:58:37 | Jane      |
+----+----------+---------------------+-----------+
| 11 | 1007     | 2017-01-07 14:58:37 | Katy      |
+----+----------+---------------------+-----------+

查询在 MySql 数据库中运行良好,结果返回如下:

+----+----------+---------------------+-----------+
| id | message_id | created_at        | name      |
+----+----------+---------------------+-----------+
| 11 | 1007     | 2017-01-07 14:58:37 | Katy      |
+----+----------+---------------------+-----------+
| 9  | 1000     | 2017-01-06 12:46:34 | Irene     |
+----+----------+---------------------+-----------+
| 5  | 1004     | 2017-01-04 09:25:45 | Emma      |
+----+----------+---------------------+-----------+

但是,在 MariaDB 数据库中,返回的结果不正确,如下所示。似乎首先按升序对message_id 进行分组,然后将orderBy 添加到其中:

+----+----------+---------------------+-----------+
| id | message_id | created_at        | name      |
+----+----------+---------------------+-----------+
| 4  | 1004     | 2017-01-03 08:20:15 | Dorothy   |
+----+----------+---------------------+-----------+
| 2  | 1007     | 2017-01-02 07:13:20 | Becky     |
+----+----------+---------------------+-----------+
| 1  | 1000     | 2017-01-01 06:03:40 | Anna      |
+----+----------+---------------------+-----------+

我尝试将查询更改为使用unique(),而不是像这样:

ChatMessages::whereIn('message_id', $messageIds)
                       ->orderBy('created_at', 'DESC')
                       ->paginate(3)
                       ->unique('message_id');

虽然它在 MariaDB 和 MySql 中的工作方式相同,但分页是在唯一检查之前应用的,因此返回的结果较少:

+----+----------+---------------------+-----------+
| id | message_id | created_at        | name      |
+----+----------+---------------------+-----------+
| 11 | 1007     | 2017-01-07 14:58:37 | Katy      |
+----+----------+---------------------+-----------+
| 9  | 1000     | 2017-01-06 12:46:34 | Irene     |
+----+----------+---------------------+-----------+

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

很可能试图做一个“groupwise max”。这不能再通过使用带有ORDER BY 的子查询的技巧来完成。

子查询,但定义,没有顺序。但是,在过去,MariaDB 和 MySQL 都会执行ORDER BY,而这恰好有利于外部查询。

MariaDB 最先忽略了内部的ORDER BY; MySQL后来接受了它。按照标签 [greatest-n-per-group] 了解各种解决方法。

【讨论】:

感谢您的回复@Rick。我正在考虑的另一种解决方法是使用 php 本身和拆分查询来完成这项工作。例如,第一个查询使用 group by 获取结果,然后使用 php 遍历循环并获取每个查询的最新条目。与之前的联合声明相比,似乎多了很多额外的查询。我会仔细阅读,看看是否还有其他解决方法。

以上是关于Laravel Eloquent groupBy orderBy 在 MariaDB 中给出不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

GroupBy() 覆盖我的选择语句 Eloquent Laravel

Laravel Eloquent GroupBy 多对一关系

Laravel 6,MYSQL - 如何使用 Laravel Querybuilder 或 Model Eloquent 将子查询与 GroupBY 左连接?

Laravel Eloquent groupBy() 并且还返回每个组的计数

Laravel Eloquent groupBy orderBy 在 MariaDB 中给出不同的结果

Laravel 按 Eloquent 关系分组