15

假设我有一个植物表:

id fruit
1  banana
2  apple
3  orange

我能做到这些

SELECT * FROM plant ORDER BY id;
SELECT * FROM plant ORDER BY fruit DESC;

这很明显。

但是我被这个咬了,这有什么用?

SELECT * FROM plant ORDER BY SUM(id);
SELECT * FROM plant ORDER BY COUNT(fruit);
SELECT * FROM plant ORDER BY COUNT(*);
SELECT * FROM plant ORDER BY SUM(1) DESC;

所有这些都只返回第一行(id = 1)。

  1. 底下发生了什么?
  2. 聚合函数会在哪些场景中派上用场ORDER BY
4

3 回答 3

24

如果您实际选择聚合值而不是表中的列,您的结果会更清楚:

SELECT SUM(id) FROM plant ORDER BY SUM(id)

这将返回所有 id 的总和。这当然是一个无用的例子,因为聚合总是只创建一行,因此不需要排序。您在查询中获得第 qith 列的原因是因为 MySQL 选择一行,不是随机的,也不是确定性的。在您的情况下,它恰好是表中的第一列,但其他人可能会根据存储引擎、主键等获得另一行。因此,仅在 ORDER BY 子句中的聚合不是很有用。

您通常想要做的是按某个字段分组,然后以某种方式对结果集进行排序:

SELECT fruit, COUNT(*)
FROM plant
GROUP BY fruit
ORDER BY COUNT(*)

现在这是一个更有趣的查询!这将为每个水果提供一行以及该水果的总数。尝试添加更多苹果,排序实际上开始变得有意义:

完整表格:

+----+--------+
| id | fruit  |
+----+--------+
|  1 | banana |
|  2 | apple  |
|  3 | orange |
|  4 | apple  |
|  5 | apple  |
|  6 | banana |
+----+--------+

上面的查询:

+--------+----------+
| fruit  | COUNT(*) |
+--------+----------+
| orange |        1 |
| banana |        2 |
| apple  |        3 |
+--------+----------+
于 2012-10-27T10:28:21.073 回答
4

在任何符合 SQL 标准的 SQL 平台上,所有这些查询都会给你一个语法错误。

SELECT * FROM plant ORDER BY SUM(id);
SELECT * FROM plant ORDER BY COUNT(fruit);
SELECT * FROM plant ORDER BY COUNT(*);
SELECT * FROM plant ORDER BY SUM(1) DESC;

例如,在 PostgreSQL 上,所有这些查询都会引发相同的错误。

错误:列“plant.id”必须出现在 GROUP BY 子句中或在聚合函数中使用

这意味着您使用域聚合函数而不使用 GROUP BY。SQL Server 和 Oracle 返回类似的错误消息。

众所周知,MySQL 的 GROUP BY 在几个方面都被破坏了,至少就标准行为而言。但是您发布的查询对我来说是一种新的破坏行为,因此为此 +1。

与其试图了解它在幕后所做的事情,不如学习编写标准的 GROUP BY 查询可能会更好。据我所知,MySQL将正确处理标准的 GROUP BY 语句。

早期版本的 MySQL 文档警告您关于 GROUP BY 和隐藏列。(我没有参考资料,但这篇文章到处都被引用了。)

如果您从 GROUP BY 部分省略的列在组中不是常量,请不要使用此功能。服务器可以自由地从组中返回任何值,因此除非所有值都相同,否则结果是不确定的。

较新的版本略有不同

您可以使用此功能通过避免不必要的列排序和分组来获得更好的性能。但是,这主要在每个未在 GROUP BY 中命名的非聚合列中的所有值对于每个组都相同时很有用。服务器可以从每个组中自由选择任何值,因此除非它们相同,否则选择的值是不确定的。

就个人而言,我不认为SQL 中的不确定特性。

于 2012-10-27T10:40:33.837 回答
2
  1. 当您使用这样的聚合时,查询会获得一个隐式组,其中整个结果是一个组。

  2. 仅当您还具有分组依据时,使用按顺序聚合的聚合才有用,以便结果中可以包含多行。

于 2012-10-27T10:34:49.980 回答