70

惊喜——这是 MySQL 中一个完全有效的查询:

select X, Y from someTable group by X

如果您在 Oracle 或 SQL Server 中尝试此查询,您会收到自然错误消息:

Column 'Y' is invalid in the select list because it is not contained in 
either an aggregate function or the GROUP BY clause.

那么 MySQL 如何确定为每个 X 显示哪个 Y?它只会选择一个。据我所知,它只会选择它找到的第一个 Y。基本原理是,如果 Y 既不是聚合函数也不是 group by 子句,那么在查询中指定“select Y”一开始就没有任何意义。因此,我作为数据库引擎将返回任何我想要的,你会喜欢的。

甚至还有一个 MySQL 配置参数来关闭这种“松散”。 http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by

这篇文章甚至提到了 MySQL 在这方面是如何被批评为不符合 ANSI-SQL 的。 http://www.oreillynet.com/databases/blog/2007/05/debunking_group_by_myths.html

我的问题是: 为什么MySQL 是这样设计的?他们打破 ANSI-SQL 的理由是什么?

4

6 回答 6

25

根据此页面(5.0 在线手册),这是为了更好的性能和用户方便。

于 2011-08-10T21:26:19.263 回答
23

我相信这是为了处理按一个字段分组意味着其他字段也被分组的情况:

SELECT user.id, user.name, COUNT(post.*) AS posts 
FROM user 
  LEFT OUTER JOIN post ON post.owner_id=user.id 
GROUP BY user.id

在这种情况下,每个 user.id 的 user.name 将始终是唯一的,因此在子句中不需要 user.name 很方便GROUP BY(尽管,正如您所说,存在一定的问题范围)

于 2009-08-04T00:06:47.570 回答
3

不幸的是,几乎所有 SQL 变体都有破坏 ANSI 并产生不可预测结果的情况。

在我看来,他们打算将其视为许多其他系统所具有的“FIRST(Y)”功能。

MySQL 团队很可能对这种结构感到遗憾,但不想因为会中断的应用程序数量而停止支持。

于 2009-08-04T00:26:38.613 回答
2

当您使用没有聚合函数的 GROUP BY 时,MySQL 将其视为单列 DISTINCT。使用其他选项,您要么使整个结果不同,要么必须使用子查询等。问题是结果是否真正可预测。

此外,这个线程中有很好的信息。

于 2012-01-04T13:27:18.937 回答
0

从我在 mysql 参考页面中读到的内容中,它说: “您可以使用此功能通过避免不必要的列排序和分组来获得更好的性能。但是,这主要在每个未在 GROUP 中命名的非聚合列中的所有值时很有用每个组的 BY 都是相同的。”

我建议你阅读这个页面(链接到 mysql 的参考手册): http ://dev.mysql.com/doc/refman/5.5/en//group-by-extensions.html

于 2013-02-15T21:11:46.320 回答
-1

它实际上是一个非常有用的工具,当您按字段分组时,所有其他字段都不必在聚合函数中。您可以通过简单地首先对其进行排序然后对其进行分组来操作将返回的结果。例如,如果我想获取用户登录信息并且想查看用户上次登录的时间,我会这样做。

USER
user_id | name

USER_LOGIN_HISTORY 
user_id | date_logged_in

USER_LOGIN_HISTORY 对一个用户有多行,所以如果我将用户加入它,它将返回很多行。因为我只对最后一个条目感兴趣,所以我会这样做

select 
  user_id,
  name,
  date_logged_in

from(

  select 
    u.user_id, 
    u.name, 
    ulh.date_logged_in

  from users as u

    join user_login_history as ulh
      on u.user_id = ulh.user_id

  where u.user_id = 1234

  order by ulh.date_logged_in desc 

)as table1

group by user_id

这将返回一行,其中包含用户名和该用户上次登录的时间。

于 2012-08-25T10:01:54.860 回答