我已经习惯了包括SQL Server在内的Microsoft技术。今天,我遇到了一个问答,其中引用了MySQL文档的以下内容:
标准SQL 会拒绝您的查询,因为您不能在聚合查询中选择不属于GROUP BY子句的非聚合字段。MySQL扩展了GROUP BY的使用,以便选择列表可以引用未在GROUP BY子句中命名的非聚合列。这意味着前面的查询在MySQL中是合法的。您可以使用此功能来避免不必要的列排序和分组,从而获得更好的性能。但是,这主要在每个未聚合列中未在GROUP BY中命名的所有值对于每个组都相同时才有用。服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则选择的值是 不确定的 。
如果该MySQL扩展与SQL标准冲突,原因是什么?
标准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的(((set函数规范))的聚合 参数 中
现在MYSQL,通过允许实现此功能 不仅 是列 函数依赖 于分组列 ,但 允许 所有列 。这给用户带来了一些问题,这些用户不了解分组的工作方式,并在他们意想不到的地方获得不确定的结果。
但是您说的很对,MySQL添加了与SQL标准冲突的功能(尽管您似乎出于错误的原因而认为)。由于他们添加了SQL标准功能,但并不是以最佳方式(更像是简单的方式),这并不完全准确,但确实与最新标准相冲突。
为了回答您的问题,我认为此MySQL功能(扩展名)的原因是符合最新的SQL标准(2003+)。为什么他们选择以这种方式实现它(不完全兼容),我们只能推测。
正如@Quassnoi和@Johan举例说明的那样,这主要是性能和可维护性问题。但是无法轻易地将RDBMS更改为足够聪明(不包括Skynet)以识别功能相关列,因此MySQL开发人员做出了选择:
我们(MySQL)为您(MySQL用户)提供了SQL-2003标准中的此功能。它可以提高某些GROUP BY查询的速度,但有一个问题。您必须小心(而不是SQL引擎),因此SELECTand HAVING列表中的列在功能上取决于GROUP BY列。如果没有,您可能会得到不确定的结果。 如果要禁用它,可以设置sql_mode为 ONLY_FULL_GROUP_BY 。
我们(MySQL)为您(MySQL用户)提供了SQL-2003标准中的此功能。它可以提高某些GROUP BY查询的速度,但有一个问题。您必须小心(而不是SQL引擎),因此SELECTand HAVING列表中的列在功能上取决于GROUP BY列。如果没有,您可能会得到不确定的结果。
GROUP BY
SELECT
HAVING
如果要禁用它,可以设置sql_mode为 ONLY_FULL_GROUP_BY 。
sql_mode
ONLY_FULL_GROUP_BY
一切都在MySQL的文档中:GROUP BY(5.5)的扩展 -尽管不在上面的措辞中,但正如您的引用一样(他们甚至忘记提及它与标准SQL-2003的差异,而不是与标准SQL-92的差异)。我认为这种选择在所有软件(包括其他RDBMS)中都是常见的。它们是出于性能,向后兼容性和许多其他原因而制造的。'' is the same as NULL例如,Oracle有名,SQL-Server也可能有一些。
'' is the same as NULL
彼得·布曼(Peter Bouman)的博客文章也捍卫了MySQL开发人员的选择:Debunking GROUP BY myths。
更新(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尊重功能依赖!