为什么MySQL允许“分组”查询没有聚合函数?

时间:2009-08-03 23:44:57

标签: sql mysql

惊喜 - 这是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的理由是什么?

6 个答案:

答案 0 :(得分:23)

根据this page(5.0在线手册),它是为了更好的性能和用户便利性。

答案 1 :(得分:19)

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

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.name将始终是每个user.id唯一的,因此在GROUP BY子句中不需要user.name是方便的(尽管如你所说,有明确的范围问题)

答案 2 :(得分:2)

不幸的是,几乎所有SQL版本都存在破坏ANSI并且具有不可预测结果的情况。

听起来我们觉得它被视为许多其他系统所具有的“FIRST(Y)”功能。

很可能,这个构造是MySQL团队后悔的东西,但是由于会破坏的应用程序数量而不想停止支持。

罗布

答案 3 :(得分:1)

当你在没有聚合函数的情况下使用GROUP BY时,MySQL认为这是一个单独的列DISTINCT。使用其他选项,您要么将整个结果区分开来,要么必须使用子查询等。问题是结果是否真的可以预测。

另外,好的信息在this thread

答案 4 :(得分:0)

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

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

答案 5 :(得分:-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

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