绕过 only_full_group_by 限制

Bypassing the only_full_group_by restriction

我有这个简单的 table:

mysql> select deviceId, eventName, loggedAt from foo;
+----------+------------+---------------------+
| deviceId | eventName  | loggedAt            |
+----------+------------+---------------------+
|        1 | foo        | 2020-09-18 21:27:21 |
|        1 | bar        | 2020-09-18 21:27:26 |
|        1 | last event | 2020-09-18 21:27:43 |  <--
|        2 | xyz        | 2020-09-18 21:27:37 |
|        2 | last event | 2020-09-18 21:27:55 |  <--
|        3 | last one   | 2020-09-18 21:28:04 |  <--
+----------+------------+---------------------+

我想 select 每 deviceId 一行,最近的 loggedAt。为了清楚起见,我在上面的 table 中用箭头标记了这些行。

如果我在上面的查询中附加 group by id,我会得到臭名昭著的:

Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'foo.eventName' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

而且我不想更改 sql_mode

我已经非常接近我想要使用的东西了:

select deviceId, any_value(eventName), max(loggedAt) from foo group by deviceId;

但显然 any_value returns 是随机结果。

我该如何解决这个问题?

ONLY_FULL_GROUP_BY 一件好事:它执行基本的 SQL 标准规则,MySQL 长期以来一直对此松懈.即使您禁用它,您也会得到与 any_value().

相同的结果

您遇到了每组排名前 1 的问题,您无法在其中 整行 包含每台设备的最新日期。聚合不是正确的工具,您需要的是过滤数据集。

一个选项使用相关子查询:

select f.*
from foo f
where f.loggedat = (
    select max(f1.loggedate) from foo where f1.deviceid = f.deviceid
)

在MySQL8.0中,也可以使用row_number():

select *
from (
    select f.*, row_number() over(partition by deviceid order by loggedat desc) rn
    from foo f
) f
where rn = 1