具有 MAX 聚合的 GROUP BY 的排序是否定义明确?

Is the ordering of a GROUP BY with a MAX aggregate well defined?

假设我 运行 SQLite 中的以下内容:

CREATE TABLE my_table
(
     id        INTEGER PRIMARY KEY,
     NAME      VARCHAR(20),
     date      DATE,
     num       INTEGER,
     important VARCHAR(20)
);

INSERT INTO my_table (NAME, date, num, important)
VALUES ('A', '2000-01-01', 10, 'Important 1');

INSERT INTO my_table (NAME, date, num, important)
VALUES ('A', '2000-02-01', 20, 'Important 2');

INSERT INTO my_table (NAME, date, num, important)
VALUES ('A', '1999-12-01', 30, 'Important 3');

table 看起来像这样:

id NAME date num important
1 A 2000-01-01 10 Important 1
2 A 2000-02-01 20 Important 2
3 A 1999-12-01 30 Important 3

如果我执行:

SELECT id
FROM   my_table
GROUP  BY NAME;

结果是:

+----+
| id |
+----+
| 1  |
+----+

如果我执行:

SELECT id, MAX(date)
FROM   my_table
GROUP  BY NAME;

结果是:

+----+------------+
| id | max(date)  |
+----+------------+
| 2  | 2000-02-01 |
+----+------------+

如果我执行:

SELECT id,
       MAX(date),
       MAX(num)
FROM   my_table
GROUP  BY NAME;

结果是:

+----+------------+----------+
| id | max(date)  | max(num) |
+----+------------+----------+
| 3  | 2000-02-01 | 30       |
+----+------------+----------+

我的问题是,这个定义好吗?具体来说,我是否保证在执行第二个查询时总是得到 id = 2 (使用单个 Max(date) 聚合),或者这只是 SQLite 可能将 table 排序为的副作用在分组之前抓住 Max?

我问这个是因为我特别想要 id = 2。然后我将执行另一个查询,该查询 select 是该行的 important 字段(对于我的实际问题,第一个查询将 return 多个 ids 我会 select 所有这些行的所有 important 个字段。

此外,这一切都发生在 iOS 核心数据查询中,因此我无法执行更复杂的子查询。如果我知道 GROUP BY 的顺序是由聚合定义的,那么我会非常有信心我的查询不会中断(直到 Apple 不再使用 SQLite for Core Data)。

谢谢!

来自 Sqlite 手册

2.5。聚合查询中的裸列

通常情况下,聚合查询中的所有列名要么是聚合函数的参数,要么出现在 GROUP BY 子句中。包含不在聚合函数内且未出现在 GROUP BY 子句(如果存在)中的列名的结果列称为“裸”列。示例:

SELECT a, b, sum(c) FROM tab1 GROUP BY a;

在上面的查询中,“a”列是 GROUP BY 子句的一部分,因此输出的每一行都包含“a”的不同值之一。 “c”列包含在 sum() 聚合函数中,因此输出列是具有相同“a”值的行中所有“c”值的总和。但是裸列“b”的结果是什么?答案是“b”结果将是构成聚合的输入行之一中“b”的值。问题是您通常不知道哪个输入行用于计算“b”,因此在许多情况下“b”的值是未定义的。

当聚合函数为 min() 或 max() 时发生特殊处理。示例:

SELECT a, b, max(c) FROM tab1 GROUP BY a;

当在聚合查询中使用 min() 或 max() 聚合函数时,结果集中的所有裸列都从输入行中获取值,该输入行也包含最小值或最大值。所以在上面的查询中,输出中“b”列的值将是输入行中具有最大“c”值的“b”列的值。如果两个或多个输入行具有相同的最小值或最大值,或者查询包含多个 min() and/or max() 聚合函数,仍然存在歧义。只有内置的 min() 和 max() 函数以这种方式工作。

如果裸列出现在缺少GROUP BY子句的聚合查询中,并且输入行数为零,则裸列的值是任意的。例如,在此查询中:

SELECT count(*), b FROM tab1;

如果 tab1 table 不包含任何行(count(*) 的计算结果为 0),则裸列“b”将具有任意且无意义的值。

大多数其他 SQL 数据库引擎不允许裸列。如果您在查询中包含裸列,其他数据库引擎通常会引发错误。在查询中包含裸列的能力是 SQLite-specific 扩展。

https://www.sqlite.org/lang_select.html

am I guaranteed to always get id = 2 when doing the second query (with the single Max(date) aggregate), or is this just a side effect of how SQLite is likely ordering the table to grab the Max before grouping?

是的,您得到的结果是有保证的,因为它记录在 Bare columns in an aggregate query

您获得的列 id 的值来自包含最大值 date 的行。