10bet网址
MySQL 8.0参考手册
相关的文档10bet官方网站 本手册下载 本手册摘录

12.20.3 MySQL处理GROUP BY

SQL-92和更早的版本不允许选择列表、条件,或命令列表中未命名的非聚合列集团条款。例如,这个查询在标准SQL-92中是非法的,因为非聚合的的名字控件中未显示集团

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

要使查询在SQL-92中是合法的,则的名字列必须从选择列表中省略或在集团条款。

SQL:1999及其后续版本允许每个可选特性T301都使用这种非聚合,如果它们在功能上依赖于它们的话集团列:如果存在这样的关系的名字custid,查询是合法的。举个例子,就是这样custid的主键客户

MySQL实现了函数依赖的检测。如果ONLY_FULL_GROUP_BY启用SQL模式(默认情况下),MySQL拒绝选择列表、条件,或命令列表引用未被命名的非聚合列集团在功能上也不依赖于它们。

MySQL还允许非聚合列没有在集团条款当SQLONLY_FULL_GROUP_BYMode已启用,前提是此列仅限于单个值,如下例所示:

mysql> CREATE TABLE mytable (-> id INT UNSIGNED NOT NULL PRIMARY KEY, -> a VARCHAR(10), -> b INT ->);mysql> INSERT INTO mytable -> VALUES (1, 'abc', 1000), -> (2, 'abc', 2000), -> (3, 'def', 4000);mysql> SET SESSION sql_mode = sys.list_add(@@session. mode)sql_mode ONLY_FULL_GROUP_BY);mysql> SELECT a, SUM(b) FROM mytable WHERE a = 'abc';+------+--------+ | 一个|和(b ) | +------+--------+ | abc | 3000  | +------+--------+

类中也可以有多个非聚合列选择当使用ONLY_FULL_GROUP_BY.在本例中,每个这样的列必须限制为在哪里所有这些限制条件必须由逻辑连接起来,如下所示:

mysql> DROP TABLE IF EXISTS mytable;mysql> CREATE TABLE mytable (-> id INT UNSIGNED NOT NULL PRIMARY KEY, -> a VARCHAR(10), -> b VARCHAR(10), -> c INT ->);mysql >插入mytable - >值(1、“abc”、“qrs”,1000年),- - - - - - > (2,' abc ',德国莱茵,2000),- - - - - - >(3“def”“qrs”,4000年),- - - - - - >(4“def”德国莱茵,8000),- - - - - - > (5 ' abc ' qrs, 16000), - - - - - - >(6“def”德国莱茵,32000);mysql >选择@@session.sql_mode;+---------------------------------------------------------------+ | @@ 会话。sql_mode  | +---------------------------------------------------------------+ | ONLY_FULL_GROUP_BY、STRICT_TRANS_TABLES NO_ENGINE_SUBSTITUTION  | +---------------------------------------------------------------+ mysql >选择a, b,和(c)从mytable - > =“abc”,b =“qrs”;+------+------+--------+ | a | | (c ) | +------+------+--------+ | abc | qrs | 17000年  | +------+------+--------+

如果ONLY_FULL_GROUP_BY是禁用的,MySQL扩展到标准SQL使用集团允许选择列表,条件,或命令列表引用非聚合列,即使这些列在功能上不依赖集团列。这将导致MySQL接受前面的查询。在这种情况下,服务器可以自由地从每个组中选择任何值,因此,除非它们相同,否则所选择的值是不确定的,这可能不是您想要的。此外,不能通过添加命令条款。结果集排序发生在选择值之后,并且命令不会影响服务器在每个组中选择的值。禁用ONLY_FULL_GROUP_BY当您知道,由于数据的某些属性,每个非聚合列中的所有值没有在集团对每一组都是相同的。

你可以在不禁用的情况下达到同样的效果ONLY_FULL_GROUP_BY通过使用ANY_VALUE ()引用非聚合列。

下面的讨论演示了函数依赖关系,当没有函数依赖关系时MySQL产生的错误消息,以及在没有函数依赖关系时导致MySQL接受查询的方法。

此查询可能无效ONLY_FULL_GROUP_BY启用是因为非聚合地址属性中未命名的选择列表中的列集团条款:

SELECT name, address, MAX(age) FROM t GROUP BY name

查询在以下情况下有效的名字主键是t或者是独一无二的非空列。在这种情况下,MySQL识别出所选列在功能上依赖于分组列。例如,如果的名字是否为主键,其值决定值地址因为每个组只有一个主键值,因此只有一行。因此,选择中没有随机性地址值,并且不需要拒绝查询。

如果是,则查询无效的名字不是的主键t或一个独特的非空列。在这种情况下,不能推断出任何函数依赖性,并会发生错误:

mysql> SELECT name, address, MAX(age) FROM t GROUP BY name;ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains non - aggregated column 'mydb.t. .在GROUP BY子句中,不依赖于列的address';这与sql_mode=only_full_group_by不兼容

如果你知道,对于给定的数据集,每一个的名字值实际上唯一地决定地址值,地址有效依赖于什么的名字.要告诉MySQL接受查询,可以使用ANY_VALUE ()功能:

SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name

另外,禁用ONLY_FULL_GROUP_BY

然而,前面的示例非常简单。特别是,不太可能对单个主键列进行分组,因为每个组将只包含一行。有关更复杂查询中演示函数依赖关系的其他示例,请参见第12.20.4节,“功能依赖的检测”

如果查询具有聚合函数且没有集团子句,则在选择列表中不能有非聚合列,条件,或命令列表,ONLY_FULL_GROUP_BY启用:

mysql> SELECT name, MAX(age) FROM t;ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'mydb.t.name';这与sql_mode=only_full_group_by不兼容

没有集团,有一个单一的群体,它是不确定的的名字值为该组选择。同样的,ANY_VALUE ()可以用,如果是非物质的哪一个的名字价值MySQL选择:

SELECT any (name), MAX(age) FROM t;

ONLY_FULL_GROUP_BY也会影响查询的处理截然不同的命令.以表为例t有三个列c1c2,c3包含以下行:

1 . C 2 . C 3 . C 4 . C

假设我们执行下面的查询,期望结果按顺序排列c3

SELECT DISTINCT c1, c2 FROM t ORDER BY c3;

要对结果排序,必须先去掉重复的结果。但要这么做,我们应该保留第一行还是第三行?这种随意的选择会影响c3,这反过来又影响了秩序,使其也变得任意。为防止此问题,可以使用具有截然不同的命令是否被视为无效命令表达式不满足以下至少一个条件:

  • 在选择列表中,表达式等于1

  • 表达式引用的所有属于查询所选表的列都是选择列表的元素

对标准SQL的另一个MySQL扩展允许在子句添加到选择列表中的别名表达式。例如,返回以下查询的名字在表中只出现一次的值订单

SELECT COUNT(name) FROM orders GROUP BY name HAVING COUNT(name) = 1;

MySQL扩展允许使用别名合计栏条款:

SELECT COUNT(name) AS c FROM orders GROUP BY name HAVING c = 1;

标准SQL只允许列表达式集团子句,所以这样的语句是无效的,因为地板(价值/ 100)是非列表达式:

SELECT id, FLOOR(value/100) FROMtbl_nameGROUP BY id, FLOOR(value/100);

MySQL扩展了标准SQL,允许非列表达式集团条款,并认为上述声明有效。

标准SQL也不允许使用别名集团条款。MySQL扩展了标准SQL,允许使用别名,所以另一种方法写查询如下:

SELECT id, FLOOR(value/100) AS val FROMtbl_nameGROUP BY id, val;

别名瓦尔中的列表达式集团条款。

中存在非列表达式时集团子句,MySQL识别出该表达式与选择列表中的表达式相等。这意味着ONLY_FULL_GROUP_BY启用SQL模式,查询包含分组id,楼层(值/100)因为这是一样的地板()表达式出现在选择列表中。然而,MySQL并没有试图识别功能依赖集团非列表达式,因此下面的查询无效ONLY_FULL_GROUP_BY控件的一个简单公式id列和地板()表达的集团条款:

SELECT id, FLOOR(value/100), id+FLOOR(value/100) FROMtbl_nameGROUP BY id, FLOOR(value/100);

解决方法是使用派生表:

SELECT id, F, id+F FROM (SELECT id, FLOOR(value/100) AS F FROMtbl_nameGROUP BY id, FLOOR(value/100)) AS dt;