基于a_horse_with_no_name在评论中提供的链接,我得出了自己的答案:
似乎 MySQL 使用 GROUP BY 的方式与 SQL 方式不同,以便允许从 GROUP BY 子句中省略列,当它们在功能上依赖于其他包含的列时。
假设我们有一个显示银行帐户活动的表格。这不是一张经过深思熟虑的桌子,但它是我们唯一拥有的一张,而且必须这样做。我们想象一个帐户从“0”开始,而不是跟踪金额,而是记录到它的所有交易,因此金额是交易的总和。该表可能如下所示:
+------------+----------+-------------+
| costumerID | name | transaction |
+------------+----------+-------------+
| 1337 | h4x0r | 101 |
| 42 | John Doe | 500 |
| 1337 | h4x0r | -101 |
| 42 | John Doe | -200 |
| 42 | John Doe | 500 |
| 42 | John Doe | -200 |
+------------+----------+-------------+
很明显,“名称”在功能上取决于“客户 ID”。(在此示例中也可以采用其他方式。)
如果我们想知道每个客户的客户 ID、姓名和当前数量怎么办?
在这种情况下,两个非常相似的查询将返回以下正确结果:
+------------+----------+--------+
| costumerID | name | amount |
+------------+----------+--------+
| 42 | John Doe | 600 |
| 1337 | h4x0r | 0 |
+------------+----------+--------+
这个查询可以在 MySQL 中执行,并且根据 SQL 是合法的。
SELECT costumerID, name, SUM(transaction) AS amount
FROM Activity
GROUP BY costumerID, name
这个查询可以在 MySQL 中执行,根据 SQL是不合法的。
SELECT costumerID, name, SUM(transaction) AS amount
FROM Activity
GROUP BY costumerID
下面的行将使查询返回和错误,因为它现在必须遵循使用聚合操作和 GROUP BY 的 SQL 方式:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
允许在 MySQL 中进行第二个查询的论点似乎是假设 SELECT 中提到但在 GROUP BY 中未提及的所有列要么在聚合操作中使用(“事务”的情况),要么是在功能上依赖于其他包含的列,(“名称”的情况)。在“name”的情况下,我们可以确保为所有组条目选择了正确的“name”,因为它在功能上依赖于“costumerID”,因此每组costumerID 只有一个可能的名称。
这种使用 GROUP BY 的方式似乎有缺陷,因为它不会对 GROUP BY 子句中遗漏的内容进行任何进一步的检查。人们可以在他们认为合适的时候从他们的 SELECT 语句中挑选列来放入他们的 GROUP BY 子句,即使包含或省略任何特定列是没有意义的。
Sailor 的例子很好地说明了这个缺陷。使用聚合运算符时(可能与 GROUP BY 结合使用),返回集中的每个组条目的每一列只有一个值。在 Sailors 的情况下,由于省略了 GROUP BY 子句,因此将整个表放入一个单独的组条目中。此条目需要名称和最大年龄。为这个条目选择一个最大年龄是很容易的,因为 MAX(S.age) 只返回一个值。但是,在 S.sname 的情况下,仅在 SELECT 中提到,现在有与整个 Sailor 表中唯一的 sname 一样多的选择(在本例中为两个,John 和 Jane Doe)。MySQL没有任何线索选择,我们没有给它任何,它也没有及时刹车,所以它只能选择先出现的东西,(Jane Doe)。如果两行互换,实际上会意外给出“正确答案”。在 MySQL 中允许这样的事情似乎很愚蠢,如果 GROUP BY 子句中遗漏了某些内容,使用 GROUP BY 的查询结果可能潜在地取决于表的顺序。显然,这就是 MySQL 的运行方式。但是,当它因为“有缺陷的”查询而不知道自己在做什么时,它至少不能礼貌地警告我们吗?我的意思是,当然,如果你给一个程序错误的指令,它可能不会(或不应该)按照你的意愿去做,但如果你给出的指令不明确,我当然不会