在 SQL 中,对有序查询的 groupby 行为是否与在同一查询中同时执行两者相同?
In SQL, does groupby on an ordered query behave the same as doing both in the same query?
以下查询是否相同,或者我可能会得到不同的结果(在任何主要数据库系统中,例如 MSSQL、MySQL、Postgres、SQLite):
在同一个查询中同时进行:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
对比在子查询中排序:
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
表格是无序的数据集。查询结果是table。因此,如果您从包含 ORDER BY
子句的子查询中 select,则该子句毫无意义;根据定义,数据集是无序的。 DBMS 可以随意忽略 ORDER BY
子句。某些 DBMS 甚至可能会发出警告或错误,但我认为更常见的是 ORDER BY
子句无效 - 至少不能保证。
在此查询中
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
您尝试按 some_other_value
排序结果。如果这是一列,则不能,因为其他列不是结果的一部分。你会得到一个语法错误。如果 some_other_value
是固定值,则没有任何顺序,因为每一行都有相同的排序键。但它可以是基于您的结果数据(组键和聚合结果)的表达式,您可以按它对结果行进行排序。
在此查询中
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
ORDER BY
子句无效。你也可以直接 select FROM my_table
:
SELECT group, some_agg_func(some_value)
FROM my_table as alias
GROUP BY group
这会得到无序的结果(或者至少不能保证每次 运行 该查询时您看到的顺序都是这样),因为您的查询没有 ORDER BY
子句.
查看第一个示例:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
让我们通过查看这个虚构的示例数据来思考 GROUP BY
做了什么:
A B
- -
1 1
1 2
然后考虑这个查询:
SELECT A
FROM SampleData
GROUP BY A
ORDER BY B
GROUP BY 子句将两行放在一个组中。然后我们想按 B
... 排序,但是组中的两行具有不同的 B 值。它应该使用哪个?
显然在这种情况下这并不重要:结果中只有一行,因此顺序无关紧要。但是一般来说,数据库怎么知道要做什么?
数据库可以猜测您想要哪个,或者只取第一个值或最后一个值——无论这些值在数据按定义无序的设置中意味着什么。事实上,这就是 MySql 会尝试为您做的:它会尝试猜测您的意思。但这个回应实在是不合适。您指定了一个不精确的查询;唯一正确的做法是抛出错误,这是大多数数据库都会做的。
现在让我们看第二个示例:
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
这里重要的是要记住数据库起源于关系集理论,我们认为的“tables”更正式地描述为无序关系。再一次:“无序”的想法在最深层次上融入了 table 的本质。
在这种情况下,内部查询可以 运行 并按指定顺序创建结果,然后外部查询可以将其与 GROUP BY 一起使用来创建一个新集合...但就像 tables,查询结果为无序关系。如果没有 ORDER BY 子句,最终结果根据定义也是无序的。
现在您可能倾向于按照您想要的顺序获得结果,但现实是所有赌注都落空了。事实上,运行 这个查询的数据库往往会按照他们第一次遇到每个组的顺序给你结果,这不会倾向于匹配 ORDER BY 因为 GROUP BY 表达式正在查看完全不同的列.其他数据库(Sql 服务器在这个组中)甚至不允许查询到 运行,尽管我可能更喜欢在这里发出警告。
现在我们来到最后一部分,我们必须重新思考问题,如下所示:
How can I use GROUP BY on the one group
column, while also ordering by some_other_column
not in the group?
答案是每个组可以包含多行,因此您必须告诉数据库要查看哪一行以获得正确的(特定的)some_other_column
值。执行此操作的典型方法是使用另一个聚合函数,它可能如下所示:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_agg_func(some_other_column)
该代码 运行 在几乎任何数据库上都不会出错。
这里要小心。一方面,当人们想要这样做时,通常是因为他们知道每个组中 some_other_column
的每条记录都具有相同的值。例如,您可以按用户 ID 进行分组,但按电子邮件进行排序,当然,具有相同用户 ID 的每条记录都应具有相同的电子邮件地址。作为人类,我们有能力做出这种推断。然而,计算机也无法处理这种思维,因此我们使用额外的聚合函数来帮助它解决问题,例如 MIN()
或 MAX()
.
另一方面,如果您不小心,有时两个不同的聚合函数会不匹配,您最终会显示组中一行的值,而使用完全不同的行以一种不好的方式对 ORDER BY 表达式进行分组。
以下查询是否相同,或者我可能会得到不同的结果(在任何主要数据库系统中,例如 MSSQL、MySQL、Postgres、SQLite):
在同一个查询中同时进行:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
对比在子查询中排序:
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
表格是无序的数据集。查询结果是table。因此,如果您从包含 ORDER BY
子句的子查询中 select,则该子句毫无意义;根据定义,数据集是无序的。 DBMS 可以随意忽略 ORDER BY
子句。某些 DBMS 甚至可能会发出警告或错误,但我认为更常见的是 ORDER BY
子句无效 - 至少不能保证。
在此查询中
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
您尝试按 some_other_value
排序结果。如果这是一列,则不能,因为其他列不是结果的一部分。你会得到一个语法错误。如果 some_other_value
是固定值,则没有任何顺序,因为每一行都有相同的排序键。但它可以是基于您的结果数据(组键和聚合结果)的表达式,您可以按它对结果行进行排序。
在此查询中
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
ORDER BY
子句无效。你也可以直接 select FROM my_table
:
SELECT group, some_agg_func(some_value)
FROM my_table as alias
GROUP BY group
这会得到无序的结果(或者至少不能保证每次 运行 该查询时您看到的顺序都是这样),因为您的查询没有 ORDER BY
子句.
查看第一个示例:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
让我们通过查看这个虚构的示例数据来思考 GROUP BY
做了什么:
A B - - 1 1 1 2
然后考虑这个查询:
SELECT A
FROM SampleData
GROUP BY A
ORDER BY B
GROUP BY 子句将两行放在一个组中。然后我们想按 B
... 排序,但是组中的两行具有不同的 B 值。它应该使用哪个?
显然在这种情况下这并不重要:结果中只有一行,因此顺序无关紧要。但是一般来说,数据库怎么知道要做什么?
数据库可以猜测您想要哪个,或者只取第一个值或最后一个值——无论这些值在数据按定义无序的设置中意味着什么。事实上,这就是 MySql 会尝试为您做的:它会尝试猜测您的意思。但这个回应实在是不合适。您指定了一个不精确的查询;唯一正确的做法是抛出错误,这是大多数数据库都会做的。
现在让我们看第二个示例:
SELECT group, some_agg_func(some_value)
FROM (
SELECT group, some_value
FROM my_table
ORDER BY some_other_value
) as alias
GROUP BY group
这里重要的是要记住数据库起源于关系集理论,我们认为的“tables”更正式地描述为无序关系。再一次:“无序”的想法在最深层次上融入了 table 的本质。
在这种情况下,内部查询可以 运行 并按指定顺序创建结果,然后外部查询可以将其与 GROUP BY 一起使用来创建一个新集合...但就像 tables,查询结果为无序关系。如果没有 ORDER BY 子句,最终结果根据定义也是无序的。
现在您可能倾向于按照您想要的顺序获得结果,但现实是所有赌注都落空了。事实上,运行 这个查询的数据库往往会按照他们第一次遇到每个组的顺序给你结果,这不会倾向于匹配 ORDER BY 因为 GROUP BY 表达式正在查看完全不同的列.其他数据库(Sql 服务器在这个组中)甚至不允许查询到 运行,尽管我可能更喜欢在这里发出警告。
现在我们来到最后一部分,我们必须重新思考问题,如下所示:
How can I use GROUP BY on the one
group
column, while also ordering bysome_other_column
not in the group?
答案是每个组可以包含多行,因此您必须告诉数据库要查看哪一行以获得正确的(特定的)some_other_column
值。执行此操作的典型方法是使用另一个聚合函数,它可能如下所示:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_agg_func(some_other_column)
该代码 运行 在几乎任何数据库上都不会出错。
这里要小心。一方面,当人们想要这样做时,通常是因为他们知道每个组中 some_other_column
的每条记录都具有相同的值。例如,您可以按用户 ID 进行分组,但按电子邮件进行排序,当然,具有相同用户 ID 的每条记录都应具有相同的电子邮件地址。作为人类,我们有能力做出这种推断。然而,计算机也无法处理这种思维,因此我们使用额外的聚合函数来帮助它解决问题,例如 MIN()
或 MAX()
.
另一方面,如果您不小心,有时两个不同的聚合函数会不匹配,您最终会显示组中一行的值,而使用完全不同的行以一种不好的方式对 ORDER BY 表达式进行分组。