神奇的SQL之层级→为什么GROUP BY之后不能直接引用原表中的列

  

GROUP BY后选择列的限制

标准SQL规定,在对表进行聚合查询的时候,只能在SELECT子句中写下面3种内容:通过GROUP BY子句指定的聚合键,聚合函数(和,AVG等),常量。我们来看个例子

我们有学生班级表(tbl_student_class)以及数据如下:

<>之前删除表如果存在tbl_student_class;   创建表tbl_student_class (   int id(8)无符号NOT NULL AUTO_INCREMENT评论的自增主键的,   sno varchar (12) NOT NULL评论“学”号,   碳氮氧varchar (5) NOT NULL评论”班级号”,   cname varchar (20) NOT NULL评论”班级名”,   主键(id)   )评论='学生班级表”;   -- ----------------------------   ——记录tbl_student_class   -- ----------------------------   插入tbl_student_class值(' 1 ',' 20190607001 ',' 0607 ','影视7班”);   插入tbl_student_class值(' 2 ',' 20190607002 ',' 0607 ','影视7班”);   插入tbl_student_class值(' 3 ',' 20190608003 ',' 0608 ','影视8班”);   插入tbl_student_class值(' 4 ',' 20190608004 ',' 0608 ','影视8班”);   插入tbl_student_class值(' 5 ',' 20190609005 ',' 0609 ','影视9班”);   插入tbl_student_class值(' 6 ',' 20190609006 ',' 0609 ','影视9班”);

我们想统计各个班(班级号,班级名)一个有多少人,以及最大的学号,我们该怎么写这个查询SQL ?我想大家应该都会

<>之前选择碳氮氧,cname,计数(sno)、马克斯(sno)   从tbl_student_class   GROUP BY cno cname;

可是有人会想了,碳氮氧和cname本来就是一对一,碳氮氧一旦确定,cname也就确定了,那SQL是不是可以这么写?

<>之前选择碳氮氧,cname,计数(sno)、马克斯(sno)   从tbl_student_class   GROUP BY cno;

执行报错了:

 (Err) 1055 -表达式# 2的选择列表不是在GROUP BY子句和包含非聚合列“test.tbl_student_class.cname”这不是功能依赖……未知,会报“字段列表中列这样的语法错误

将| |视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数CONCAT()相类似

使用显示创建表时不会输出MySQL特有的语法部分,如引擎,这个在使用,mysqldump跨DB种类迁移的时候需要考虑

字面意思不自动创建用户。在给MySQL用户授权时,我们习惯使用格兰特……alt="神奇的SQL之层级→为什么GROUP BY之后不能直接引用原表中的列">


我们可以看的到,5.7.21的默认模式包含:

 ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION 

而第一个:ONLY_FULL_GROUP_BY就会约束:当我们进行聚合查询的时候,选择的列不能直接包含非GROUP BY子句中的列。那如果我们去掉该模式(从“严格模式”到“宽松模式”)呢?

神奇的SQL之层级→为什么GROUP BY之后不能直接引用原表中的列


我们发现,上述报错的SQL

——宽松模式下可以执行
  选择碳氮氧、cname计数(sno)、马克斯(sno)
  从tbl_student_class
  GROUP BY cno;

能正常执行了,但是一般情况下不推荐这样配置,线上环境往往是“严格模式”,而不是“宽松模式”;虽然案例中,无论是“严格模式”,还是“宽松模式”,结果都是对的,那是因为 cno 与 cname 唯一对应的,如果 cno 与 cname 不是唯一对应,那么在“宽松模式下” cname 的值是随机的,这就会造成难以排查的问题,有兴趣的可以去试试。那为什么会有 alt="神奇的SQL之层级 →为什么 GROUP BY 之后不能直接引用原表中的列">


谈到了阶,就不得不谈下集合论;集合论是 SQL 语言的根基,因为它的这个特性,SQL 也被称为面向集合语言。只有从集合的角度来思考,才能明白 SQL 的强大威力。通过上图,相信大家也都能看到,这里不做更深入的讲解了,有兴趣的可以去查相关资料。

为什么聚合后不能再引用原表中的列

很多人都知道聚合查询的限制,但是很少有人能正确地理解为什么会有这样的约束。表 tbl_student_class 中的 cname 存储的是每位学生的班级信息,但需要注意的是,这里的 cname 只是每个学生的属性,并不是小组的属性,而 GROUP BY 又是聚合操作,操作的对象就是由多个学生组成的小组,因此,小组的属性只能是平均或者总和等统计性质的属性,如下图

神奇的SQL之层级→为什么GROUP BY之后不能直接引用原表中的列