MySQL - 选择不在Group By中的列

col*_*ium 48 mysql group-by

我正在尝试向预先存在的应用程序添加功能,我遇到了类似这样的MySQL视图:

SELECT
     AVG(table_name.col1),
     AVG(table_name.col2),
     AVG(table_name.col3),
     table_name.personID,
     table_name.col4
FROM table_name
GROUP BY table_name.personID;
Run Code Online (Sandbox Code Playgroud)

好的,所以有一些聚合函数.您可以选择personID,因为您正在对其进行分组.但它也是选择一个不在聚合函数中的列,而不是GROUP BY子句的一部分.这怎么可能???它只是选择一个随机值,因为每个组的值绝对不是唯一的吗?

我来自哪里(MSSQL Server),这是一个错误.有人可以向我解释这种行为以及为什么它在MySQL中被允许?

Bil*_*win 48

确实,此功能允许一些不明确的查询,并以一个从该列中选取的任意值静默返回结果集.实际上,它往往是首先物理存储的组内行的值.

如果您只选择功能上依赖于GROUP BY条件中的列的列,则这些查询不会模糊.换句话说,如果每个定义组的值只有一个"模糊"列的不同值,则没有问题.此查询在Microsoft SQL Server(和ANSI SQL)中是非法的,即使它在逻辑上不会导致歧义:

SELECT AVG(table1.col1), table1.personID, persons.col4
FROM table1 JOIN persons ON (table1.personID = persons.id)
GROUP BY table1.personID;
Run Code Online (Sandbox Code Playgroud)

此外,MySQL有一个SQL模式,使其符合标准: ONLY_FULL_GROUP_BY

FWIW,SQLite也允许这些不明确的GROUP BY子句,但它选择组中最后一行的值.


至少在我测试的版本中.任意意味着MySQL或SQLite可能在未来改变它们的实现,并且有一些不同的行为.因此,您不应该依赖于他们目前处于模糊情况的行为.最好将您的查询重写为确定性而不是模糊不清.这就是MySQL 5.7现在默认启用ONLY_FULL_GROUP_BY的原因.

  • 我想说这不完全正确.从ANSI SQL-99开始,所选字段必须是聚合,在功能上依赖于group by子句.因此,在按user_id分组时选择user_name是完全正常的.SQL Server和Oracle不符合这一点,因为当只有user_id在group by列表中时,它们不允许选择user_name; 并且MySQL不符合,因为它不检查所选的每个列是否真的在功能上依赖于user_id. (4认同)

col*_*ium 12

我应该用谷歌搜索一下......似乎我找到了答案.

MySQL扩展了GROUP BY的使用,以便您可以在SELECT列表中使用未出现在GROUP BY子句中的非聚合列或计算.您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能.例如,您不需要在以下查询中对customer.name进行分组

在标准SQL中,您必须将customer.name添加到GROUP BY子句中.在MySQL中,名称是多余的.

不过,这似乎......错了.

  • 你是对的,这似乎是错的.它是!虽然我确定存在一些异常情况,正如Bill Karwin上面所指出的那样,我经常看到开发人员,他们不了解数据或者这个功能如何真正起作用,用不合适的group by子句编写查询并获得不好的结果.默认情况下,此功能应处于关闭状态,并允许使用查询选项有意覆盖该功能,以便在工程师获得足够信息使用它时使用. (4认同)
  • 没有比让 `SELECT * FROM table1` 以给定的、一致的顺序返回结果更“错误”:这是一个特性,而不是一个错误。 (2认同)
  • @kmoser 这显然是“更错误”(更糟糕:))。SQL 被定义为基于集合的语言,集合中元素的顺序是无关的。只要表的记录不更改,“SELECT * FROM table1”就会返回同一组记录。相比之下,GROUPed 查询将返回不同的记录集,具体取决于记录插入表中的顺序。这绝对是错误的。与许多其他与 mysql 相关的东西类似,这是一个危险的陷阱,mysql 试图将其作为“功能”进行销售。 (2认同)