为什么Mysql的Group By和Oracle的Group通过行为是不同的

Chi*_*Gor 7 mysql sql oracle group-by aggregate-functions

为什么Mysql的Group By和Oracle的Group通过行为是不同的

我发现很多次Mysql的groupBy功能和Oracle的GroupBy功能表现不同

很多时候我在Oracle中发现了错误(这实际上是错误的查询)但是Mysql会给出结果

所以这个Mysql奇怪的行为背后有任何原因

O. *_*nes 13

MySQL设计人员进行了非标准扩展,GROUP BY试图使开发更容易,某些查询更有效.

这是他们的理由.

https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html

有一种服务器模式ONLY_FULL_GROUP_BY可以禁用非标准扩展.您可以使用此语句设置此模式.

 SET SESSION SQL_MODE='ONLY_FULL_GROUP_BY'  
Run Code Online (Sandbox Code Playgroud)

这是该页面的引用,重点是增加.

如果ONLY_FULL_GROUP_BY禁用,则标准SQL使用的MySQL扩展GROUP BY允许选择列表,HAVING条件或ORDER BY列表引用非聚合列,即使列在功能上不依赖于GROUP BY列...在这种情况下,服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的,这可能不是您想要的.

这里重要的一点是不确定的. 那是什么意思?这意味着 随机,但更糟.如果服务器选择了随机值,这意味着它将在不同的查询中返回不同的值,因此您在测试软件时有机会发现问题.但是在这种情况下不确定意味着服务器每次都选择相同的值,直到它没有.

为什么它会改变它选择的价值?服务器升级是一个原因.表大小的更改可能是另一个.关键是,服务器可以自由返回它想要的任何值.

我希望人们新学习SQL会设置这种ONLY_FULL_GROUP_BY模式; 他们从查询中获得更可预测的结果,服务器会拒绝非确定性查询.


Gar*_*thD 9

Oracle不扩展旧的SQL标准,该标准声明选择列表中未包含在聚合函数中的所有项都必须包含在group by子句中.

MySQL的文档状态:


在标准SQL中,包含GROUP BY子句的查询不能引用选择列表中未在GROUP BY子句中指定的非聚合列.例如,此查询在标准SQL中是非法的,因为选择列表中的名称列不会出现在GROUP BY中:

SELECT o.custid, c.name, MAX(o.payment)
  FROM orders AS o, customers AS c
  WHERE o.custid = c.custid
  GROUP BY o.custid;
Run Code Online (Sandbox Code Playgroud)

要使查询合法,必须从选择列表中省略name列,或在GROUP BY子句中指定name列.

MySQL扩展了GROUP BY的使用,因此选择列表可以引用GROUP BY子句中未命名的非聚合列.这意味着前面的查询在MySQL中是合法的.您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能.但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用.


所以回答你的问题,为什么MySQL这样做最相关的提取是:

您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能.但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用.

我总是主张避开这个特定的MySQL扩展,除非你完全理解它.

想象一下下面的简单表(T):

ID  | Column1 | Column2  |
----|---------+----------|
1   |    A    |    X     |
2   |    A    |    Y     |
Run Code Online (Sandbox Code Playgroud)

在MySQL中你可以写

SELECT  ID, Column1, Column2
FROM    T
GROUP BY Column1;
Run Code Online (Sandbox Code Playgroud)

这实际上打破了SQL标准,但它适用于MySQL,但问题是它是非确定性的,结果是:

ID  | Column1 | Column2  |
----|---------+----------|
1   |    A    |    X     |
Run Code Online (Sandbox Code Playgroud)

没有或多或少不正确

ID  | Column1 | Column2  |  
----|---------+----------|
2   |    A    |    Y     |
Run Code Online (Sandbox Code Playgroud)

所以你所说的是给我一行,每个不同的值Column1,两个结果集都满足,所以你怎么知道你会得到哪一个?嗯,你没有,似乎是一个相当流行的误解,你可以添加和ORDER BY子句来影响结果,所以例如以下查询:

SELECT  ID, Column1, Column2
FROM    T
GROUP BY Column1
ORDER BY ID DESC;
Run Code Online (Sandbox Code Playgroud)

确保您获得以下结果:

ID  | Column1 | Column2  |  
----|---------+----------|
2   |    A    |    Y     |
Run Code Online (Sandbox Code Playgroud)

因为ORDER BY ID DESC,但事实并非如此(如此处所示).

MySQL的文件状态:

服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的.此外,添加ORDER BY子句不会影响每个组中值的选择.

因此,即使您有一个订单,但在每个组选择了一行之后才会适用,并且这一行是不确定的.

SQL-Standard允许选择列表中的列不包含在GROUP BY中或聚合函数中,但是这些列必须在功能上依赖于GROUP BY中的列.从SQL-2003-Standard:

15)如果T是分组表,那么令G为T的分组列的集合.在每个包含的列中,引用T列的每个列引用应引用某些在功能上依赖于G或应包含的列C在聚合查询为QS的聚合参数中.

例如,示例表中的ID是PRIMARY KEY,因此我们知道它在表中是唯一的,因此以下查询符合SQL标准并且将在MySQL中运行并且当前在许多DBMS中失败(在编写Postgresql时)是我所知道的最接近正确实施标准的DBMS - 例如:

SELECT  ID, Column1, Column2
FROM    T
GROUP BY ID;
Run Code Online (Sandbox Code Playgroud)

由于ID对于每一行都是唯一的,因此Column1每个ID 只能有一个值,一个值Column2对于每行返回的内容没有歧义.