查看第一个样本:
SELECT group, some_agg_func(some_value)
FROM my_table
GROUP BY group
ORDER BY some_other_value
让我们通过查看这个虚构的样本数据来思考GROUP BY 做了什么:
甲乙
- -
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
这里重要的是要记住数据库起源于关系集合论,我们认为的“表”更正式地描述为无序关系。再说一遍:“无序”的概念在最深层次上已经融入了表格的本质。
在这种情况下,内部查询可以按指定的顺序运行并创建结果,然后外部查询可以将其与 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 表达式的方式不好。