为什么MySQL添加了与SQL标准冲突的功能?

rah*_*rma 9 mysql

我习惯了Microsoft技术,包括SQL Server.今天我遇到了一个Q&A,其中引用了MySQL文档中的以下段落:

标准SQL会拒绝您的查询,因为您无法在聚合查询中选择不属于GROUP BY子句的非聚合字段.MySQL扩展了GROUP BY的使用,因此选择列表可以引用GROUP BY子句中未命名的非聚合列.这意味着前面的查询在MySQL中是合法的.您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能.但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用.服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是 不确定的.

如果它与SQL标准冲突,这个MySQL扩展的原因是什么?

ype*_*eᵀᴹ 22

标准SQL会拒绝你的查询,因为你无法选择非集合字段不是该组的一部分BY子句在聚合查询

这是正确的,直到1992年.

但从2003年及以后,显然错误的.

来自SQL-2003标准,6IWD6-02-Foundation-2011-01.pdf,来自http://www.wiscorp.com/,第7.12段(查询规范),第398页:

17)如果T是分组表,那么让G为T的分组列的集合.在((选择列表))中包含的每个((值表达式))中,引用T列的每个列引用应引用一些功能上依赖于G的列C 或者包含在((集函数规范))的聚合参数中,其聚合查询是QS


现在,MYSQL通过不仅允许功能上依赖于分组列允许所有列的列来实现此功能.这会导致用户无法理解分组如何工作并在不期望的情况下获得不确定的结果.

但你说对MySQL添加了一个与SQL标准冲突的功能是正确的(尽管你似乎认为这是错误的原因).它并不完全准确,因为它们添加了SQL标准功能但不是最好的方式(更像是简单方法),但它确实与最新标准冲突.

为了回答你的问题,我认为这个MySQL功能(扩展)的原因是符合最新的SQL标准(2003+).为什么他们选择以这种方式实现它(不完全符合),我们只能推测.

由于@Quassnoi和@Johan回答了一些例子,它主要是性能和可维护性问题.但是人们不能轻易地将RDBMS变得足够聪明(Skynet排除)以识别功能相关的列,因此MySQL开发人员做出了选择:

我们(MySQL)为您(MySQL用户)提供了这个SQL-2003标准的功能.它提高了某些GROUP BY查询的速度,但有一个问题.您必须小心(而不是SQL引擎),因此SELECTHAVING列表中的列在功能上依赖于GROUP BY列.如果没有,您可能会得到不确定的结果.

如果要禁用它,可以设置sql_modeONLY_FULL_GROUP_BY.

这些都在MySQL文档中:扩展到GROUP BY(5.5) - 虽然不是在上面的措辞中,但在你的引用中(他们甚至忘记提到它是偏离标准SQL-2003而不是标准SQL-92).我认为在所有软件中都有这种选择,包括其他RDBMS.它们是出于性能,向后兼容性和许多其他原因而制造的.Oracle就是着名'' is the same as NULL的例子,而SQL-Server也可能有一些.

还有一篇由Peter Bouman 撰写的博客文章,其中MySQL开发人员的选择得到了辩护:Debunking GROUP BY神话.


更新(2011年)

正如@Mark Byers在评论中提到的那样(在DBA.SE的相关问题中),PostgreSQL 9.1增加了一个为此目的而设计的新功能(发布日期:2011年9月).它比MySQL的实现更具限制性,更接近标准.


更新2(2015)

MySQL宣布在5.7版本中,行为得到改进,以符合标准并实际识别功能依赖性(甚至比Postgres实现更好).文档:MySQL处理GROUP BY(5.7)和Peter Bouman撰写的另一篇博文:MySQL 5.7.5:GROUP BY尊重功能依赖!

  • 只需添加到您的集合:在`SQL Server`中,`NULL`可以违反唯一约束. (2认同)

Qua*_*noi 7

如果它与SQL标准冲突,这个MySQL扩展的原因是什么?

它允许您编写如下查询:

SELECT  a.*, COUNT(*)
FROM    a
JOIN    b
ON      b.a = a.id
GROUP BY
        a.id
Run Code Online (Sandbox Code Playgroud)

其他系统要求您将所有列添加aGROUP BY列表中,这会使查询更大,更少可维护且效率更低.

在这种形式中(通过分组PK),这与标准不矛盾,因为每个列在a功能上都依赖于其主键.

但是,MySQL并不真正检查功能依赖性,并允许您选择非功能依赖于分组集的列.这可能会产生不确定的结果,不应该依赖.唯一保证的是列值属于共享分组表达式的一些记录(甚至不是一个记录!).

可以通过设置sql_mode为禁用此行为ONLY_FULL_GROUP_BY.