MySQL中的Group By是否允许SELECT非聚合列的总结

Posted javartisan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL中的Group By是否允许SELECT非聚合列的总结相关的知识,希望对你有一定的参考价值。

样例数据:

数据库表结构:

CREATE TABLE `student` (
  `sno` varchar(20) NOT NULL,
  `sname` varchar(20) DEFAULT NULL,
  `ssex` varchar(20) DEFAULT NULL,
  `sage` int(11) DEFAULT NULL,
  `sdept` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`sno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

数据库表数据:

INSERT INTO databasebook.student (sno, sname, ssex, sage, sdept) VALUES ('201215121', '李勇', '男', 20, 'CS');
INSERT INTO databasebook.student (sno, sname, ssex, sage, sdept) VALUES ('201215122', '刘晨', '女', 19, 'CS');
INSERT INTO databasebook.student (sno, sname, ssex, sage, sdept) VALUES ('201215123', '王敏', '女', 18, 'MA');
INSERT INTO databasebook.student (sno, sname, ssex, sage, sdept) VALUES ('201215124', '张立', '男', 19, 'IS');
INSERT INTO databasebook.student (sno, sname, ssex, sage, sdept) VALUES ('201215125', '张立', '男', 19, 'IS');

业务场景以及解决方案

业务场景:在业务开发时候遇见一场景需要根据某几个字段进行去重选择出所有出重之后的Row,在本文中可以认为是需要对ssex进行去重,在性别为男、性别为女的中各选择一条记录即可。于是在公司的测试数据库编写SQL为:

SELECT s.* from student s  GROUP BY s.ssex ;

查询结果:

snosnamessexsagesdept
201215121李勇20CS
201215122刘晨19CS

满足需要,但是随后切换到本地的mysql执行该SQL发现报错,错误信息如下:

[42000][1055] Expression #1 of SELECT list is not in GROUP BY clause and 
contains nonaggregated column 'databasebook.s.sno' which is not functionally
 dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

错误信息很明显,存在SELECT的列不在GROUP BY中,因此只能根据错误信息顺藤摸瓜了,寻找错误根源,MYSQL官网如下:MYSQL官方解释 如下:

SQL92以及更早的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;

因为c.name没有在group中,因此解决方案是删除c.name或者将c.name添加到group by中。但是在后期的SQL99标准中便允许查询非聚合的列了。

 

在MYSQL的5.7.5以及以上版本默认的设置是:ONLY_FULL_GROUP_BY  ,该设置则约束查询必须是聚合的列。但是在其版本之前则允许查询非聚合的列。我本地MYSQL是:5.7.22-log,公司的版本是:5.5.50-MariaDB。更多细节参考:SQL_MODE 。如果ONLY_FULL_GROUP_BY 开启的但是还想查询非聚合的列可以使用ANY_VALUE(非聚合列)进行查询,ANY_VALUE参考文档。还有一种情况开启ONLY_FULL_GROUP_BY时,如果GROUP BY是主键或者 unique NOT NULL 时是可以查询非聚合的列的,原因是此时分组的key是主键,则每一个分组只有一条数据,因此是可以进行查询非聚合的列的。最后对于高于5.7.5的版本如果想查询非聚合的列可以关闭ONLY_FULL_GROUP_BY 属性,即:

set sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

 

关于sql_mode系统变量说明

根据sql_mode的系统变量值MYSQL服务器可以工作在不同的SQL模式下,sql_mode主要影响的是sql的语法该变量可以使得MYSQL更容易与与其他DB Server一起协作。关于sql_mode的一切高频次问题参见:高频次问题答案

设置sql_mode的变量值方式

  1. 命令行参数:--sql-mode="modes" 
  2. 配置文件:my.cnf
  3. 运行时修改:SET GLOBAL sql_mode = 'modes';或者SET SESSION sql_mode = 'modes'; 作用域的差别而已。

查看sql_mode的变量值

SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;

sql_mode几个比较重要的值

参见:https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html

 

以上是关于MySQL中的Group By是否允许SELECT非聚合列的总结的主要内容,如果未能解决你的问题,请参考以下文章

group by having用法举例

GROUP BY中的字段是否必须在SELECT中

GROUP BY中的字段是否必须在SELECT中

mysql中的select语句where条件group by ,having , order by,limit的顺序及用法

Mysql--Cause: java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY

MySQL 5.7默认ONLY_FULL_GROUP_BY语义介绍