在 SQL 中,有序查询中的 groupby 行为是不是与在同一查询中执行相同?
Posted
技术标签:
【中文标题】在 SQL 中,有序查询中的 groupby 行为是不是与在同一查询中执行相同?【英文标题】:In SQL, does groupby on an ordered query behave the same as doing both in the same query?在 SQL 中,有序查询中的 groupby 行为是否与在同一查询中执行相同? 【发布时间】:2021-08-27 21:16:18 【问题描述】:以下查询是否相同,或者我可能得到不同的结果(在任何主要的数据库系统中,例如 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
【问题讨论】:
MS Sql Server 不会运行任何一个查询:第一个是因为它引用了 group by 之外的原始表中的列,并且由于 group by 几乎按照定义为每个组汇总多行,您可以'不确定要查看每组中的哪一行来获取值。嵌套选择中的第二个顺序是没有意义的。理论上它不应该受到伤害,但它肯定无济于事,在实践中几乎总是意味着错误,所以 Sql Server 会告诉你这一点。就个人而言,我更喜欢在这里发出警告,但是嗯。 【参考方案1】:表格是无序的数据集。查询结果是一个表。因此,如果您从包含ORDER BY
子句的子查询中进行选择,则该子句没有任何意义;数据集根据定义是无序的。 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
子句无效。你也可以直接选择FROM my_table
:
SELECT group, some_agg_func(some_value)
FROM my_table as alias
GROUP BY group
这会使结果无序(或者至少每次运行该查询时都不能保证您看到的顺序),因为您的查询没有ORDER BY
子句。
【讨论】:
【参考方案2】:查看第一个样本:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
让我们通过查看这个虚构的样本数据来思考GROUP BY
做了什么:
然后想想这个查询:
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
这里重要的是要记住数据库起源于关系集合论,我们认为的“表”更正式地描述为无序关系。再说一遍:“无序”的概念在最深层次上已经融入了表格的本质。
在这种情况下,内部查询可以按指定的顺序运行并创建结果,然后外部查询可以将其与 GROUP BY 一起使用来创建一个新集合...但是就像表一样,查询结果是无序的关系。如果没有 ORDER BY 子句,最终结果也是按定义无序的。
现在您可能倾向于按照您想要的顺序获得结果,但现实情况是所有的赌注都没有了。事实上,运行此查询的数据库往往会按照它们第一次遇到每个组的顺序为您提供结果,这不会与 ORDER BY 匹配,因为 GROUP BY 表达式正在查看完全不同的列。其他数据库(Sql Server 在这个组中)甚至不允许查询运行,尽管我可能更喜欢这里的警告。
所以现在我们来到最后一部分,我们必须重新思考这个问题,如下所示:
如何在
group
列上使用 GROUP BY,同时按不在组中的some_other_column
排序?
答案是每个组可以包含多行,因此您必须告诉数据库要查看哪一行才能获得正确的(特定的)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 表达式的方式不好。
【讨论】:
以上是关于在 SQL 中,有序查询中的 groupby 行为是不是与在同一查询中执行相同?的主要内容,如果未能解决你的问题,请参考以下文章