in ms sql 集合参数传递_神奇的 SQL → 为什么 GROUP BY 之后不能直接引用原表中的列?...

GROUP BY 后 SELECT 列的限制

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

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

DROP TABLE IF EXISTS tbl_student_class;CREATE TABLE tbl_student_class (  id int(8) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',  sno varchar(12) NOT NULL COMMENT '学号',  cno varchar(5) NOT NULL COMMENT '班级号',  cname varchar(20) NOT NULL COMMENT '班级名',  PRIMARY KEY (id)) COMMENT='学生班级表';-- ------------------------------ Records of tbl_student_class-- ----------------------------INSERT INTO tbl_student_class VALUES ('1', '20190607001', '0607', '影视7班');INSERT INTO tbl_student_class VALUES ('2', '20190607002', '0607', '影视7班');INSERT INTO tbl_student_class VALUES ('3', '20190608003', '0608', '影视8班');INSERT INTO tbl_student_class VALUES ('4', '20190608004', '0608', '影视8班');INSERT INTO tbl_student_class VALUES ('5', '20190609005', '0609', '影视9班');INSERT INTO tbl_student_class VALUES ('6', '20190609006', '0609', '影视9班');

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

SELECT cno,cname,count(sno),MAX(sno) FROM tbl_student_classGROUP BY cno,cname;

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

SELECT cno,cname,count(sno),MAX(sno) FROM tbl_student_classGROUP BY cno;

执行报错了:

[Err] 1055 - Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tbl_student_class.cname' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

提示信息:SELECT 列表中的第二个表达式(cname)不在 GROUP BY 的子句中,同时它也不是聚合函数;这与 sql 模式:ONLY_FULL_GROUP_BY 不相容。

为什么 GROUP BY 之后不能直接引用原表(不在 GROUP BY 子句)中的列 ?莫急,我们慢慢往下看。

SQL 模式

MySQL 服务器可以在不同的 SQL 模式下运行,并且可以针对不同的客户端以不同的方式应用这些模式,具体取决于 sql_mode 系统变量的值。DBA 可以设置全局SQL模式以匹配站点服务器操作要求,并且每个应用程序可以将其会话 SQL 模式设置为其自己的要求。

模式会影响 MySQL 支持的 SQL 语法以及它执行的 数据验证检查,这使得在不同环境中使用MySQL以及将MySQL与其他数据库服务器一起使用变得更加容易。更多详情请查阅官网:Server SQL Modes。

MySQL 版本不同,内容会略有不同(包括默认值),查阅的时候注意与自身的 MySQL 版本保持一致。

SQL 模式主要分两类:语法支持类和数据检查类,常用的如下

语法支持类    

  • ONLY_FULL_GROUP_BY

对于 GROUP BY 聚合操作,如果在 SELECT 中的列、HAVING 或者 ORDER BY 子句的列,没有在GROUP BY中出现,那么这个SQL是不合法的

  • ANSI_QUOTES

启用 ANSI_QUOTES 后,不能用双引号来引用字符串,因为它被解释为识别符,作用与 ` 一样。设置它以后,update t set f1="" …,会报 Unknown column ‘’ in field list 这样的语法错误

  • PIPES_AS_CONCAT

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

  • NO_TABLE_OPTIONS

使用 SHOW CREATE TABLE 时不会输出MySQL特有的语法部分,如 ENGINE ,这个在使用 mysqldump 跨DB种类迁移的时候需要考虑

  • NO_AUTO_CREATE_USER

字面意思不自动创建用户。在给MySQL用户授权时,我们习惯使用 GRANT … ON … TO dbuser 顺道一起创建用户。设置该选项后就与oracle操作类似,授权之前必须先建立用户

数据检查类   

  • NO_ZERO_DATE

认为日期 ‘0000-00-00’ 非法,与是否设置后面的严格模式有关

1、如果设置了严格模式,则 NO_ZERO_DATE 自然满足。但如果是 INSERT IGNORE 或 UPDATE IGNORE,’0000-00-00’依然允许且只显示warning;

2、如果在非严格模式下,设置了NO_ZERO_DATE,效果与上面一样,’0000-00-00’ 允许但显示warning;如果没有设置NO_ZERO_DATE,no warning,当做完全合法的值;

3、NO_ZERO_IN_DATE情况与上面类似,不同的是控制日期和天,是否可为 0 ,即 2010-01-00 是否合法;

  • NO_ENGINE_SUBSTITUTION

使用 ALTER TABLE 或 CREATE TABLE 指定 ENGINE 时, 需要的存储引擎被禁用或未编译,该如何处理。启用 NO_ENGINE_SUBSTITUTION 时,那么直接抛出错误;不设置此值时,CREATE用默认的存储引擎替代,ATLER不进行更改,并抛出一个 warning

  • STRICT_TRANS_TABLES

设置它,表示启用严格模式。注意 STRICT_TRANS_TABLES 不是几种策略的组合,单独指 INSERT、UPDATE 出现少值或无效值该如何处理:

1、前面提到的把 ‘’ 传给int,严格模式下非法,若启用非严格模式则变成 0,产生一个warning;

2、Out Of Range,变成插入最大边界值;

3、当要插入的新行中,不包含其定义中没有显式DEFAULT子句的非NULL列的值时,该列缺少值;

默认模式

当我们没有修改配置文件的情况下,MySQL 是有自己的默认模式的;版本不同,默认模式也不同

-- 查看 MySQL 版本SELECT VERSION();-- 查看 sql_modeSELECT @@sql_mode;
3956a93e20bd11bd7ae06891fc810072.gif

我们可以看到,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 就会约束:当我们进行聚合查询的时候,SELECT 的列不能直接包含非 GROUP BY 子句中的列。那如果我们去掉该模式(从“严格模式”到“宽松模式”)呢 ?

46f281c3a8d90128f470bccc07debb03.gif

我们发现,上述报错的 SQL

-- 宽松模式下 可以执行SELECT cno,cname,count(sno),MAX(sno) FROM tbl_student_classGROUP BY cno;

能正常执行了,但是一般情况下不推荐这样配置,线上环境往往是“严格模式”,而不是“宽松模式”;虽然案例中,无论是“严格模式”,还是“宽松模式”,结果都是对的,那是因为 cno 与 cname 唯一对应的,如果 cno 与 cname 不是唯一对应,那么在“宽松模式下” cname 的值是随机的,这就会造成难以排查的问题,有兴趣的可以去试试。那为什么会有 ONLY_FULL_GROUP_BY 模式呢 ? 我们继续往下看

阶(order)是用来区分集合或谓词的阶数的概念。谓词逻辑中,根据输入值的阶数对谓词进行分类。

= 或者 BETWEEEN 等输入值为一行的谓词叫作"一阶谓词",而像 EXISTS 这样输入值为行的集合的谓词叫作"二阶谓词"(HAVING 的输入值也是集合,但它不是谓词)。以此类推,三阶谓词=输入值为"集合的集合"的谓词,四阶谓词=输入值为"集合的集合的集合"的谓词,但是 SQL 里并不会出现三阶以上的情况,所以不用太在意。

简单点如下图

a6d9219725a9dfc4bcb08f98ba6ad982.png

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

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

很多人都知道聚合查询的限制,但是很少有人能正确地理解为什么会有这样的约束。表 tbl_student_class 中的 cname 存储的是每位学生的班级信息。

但需要注意的是,这里的 cname 只是每个学生的属性,并不是小组的属性,而 GROUP BY 又是聚合操作,操作的对象就是由多个学生组成的小组,因此,小组的属性只能是平均或者总和等统计性质的属性,如下图

8211d4b825e7dfac4d52472c1ed968ba.png

询问每个学生的 cname 是可以的,但是询问由多个学生组成的小组的 cname 就没有意义了。对于小组来说,只有"一共多少学生"或者"最大学号是多少?"这样的问法才是有意义的。

强行将适用于个体的属性套用于团体之上,纯粹是一种分类错误;而 GROUP BY 的作用是将一个个元素划分成若干个子集,使用 GROUP BY 聚合之后,SQL 的操作对象便由 0 阶的"行"变为了 1 阶的"行的集合",此时,行的属性便不能使用了。

SQL 的世界其实是层级分明的等级社会,将低阶概念的属性用在高阶概念上会导致秩序的混乱,这是不允许的。此时我相信大家都明白:为什么聚合后不能再引用原表中的列 。

单元素集合也是集合

现在的集合论认为单元素集合是一种正常的集合。单元素集合和空集一样,主要是为了保持理论的完整性而定义的。因此对于以集合论为基础的 SQL 来说,当然也需要严格地区分元素和单元素集合。因此,元素 a 和集合 {a} 之间存在着非常醒目的层级差别。

a ≠ {a}

这两个层级的区别分别对应着 SQL 中的 WHERE 子句和 HAVING 子句的区别。WHERE 子句用于处理"行"这种 0 阶的对象,而 HAVING 子句用来处理"集合"这种 1 阶的对象。

总结

1、SQL 严格区分层级,包括谓词逻辑中的层级(EXISTS),也包括集合论中的层级(GROUP BY);

2、有了层级区分,那么适用于个体上的属性就不适用于团体了,这也就是为什么聚合查询的 SELECT 子句中不能直接引用原表中的列的原因;

3、一般来说,单元素集合的属性和其唯一元素的属性是一样的。这种只包含一个元素的集合让人觉得似乎没有必要特意地当成集合来看待,但是为了保持理论的完整性,我们还是要严格区分元素和单元素集合;

参考

《SQL基础教程》《SQL进阶教程》

Java知音,专注于Java实用文章推送,不容错过!

来源:cnblogs.com/youzhibing/p/11516154.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529576.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器日志文件中包含堆栈跟踪,日志框架 Logback 官方手册(第三章:Configuration)...

以下内容翻译整理自logback官方手册,地址:logback官方手册logback 配置将日志请求插入应用程序代码需要相当多的计划和工作。观察表明,大约有4%的代码用于日志记录。因此,即使是一个中等大小的应用程序,其代码中也会包…

extjs 月份选择控件_Excel | 做个生日提醒控件,本月或下月过生日的员工信息随你查看...

问题情境掌握职工的生日信息,及时送出生日祝福,是每位HR必备的技能。某公司要求将公司的员工生日信息实现查询,可方便的查看本月及下月过生日的员工信息,效果如下动图:效果中可以看出:勾选”本月生日“&…

音频服务器未显示,Win7系统没有声音提示“一个或多个音频服务未运行”如何解决...

在win7系统中没有声音,点击右下角小喇叭,按照提示进行修复完成后的“疑难解答已完成”界面,提示已找到问题“一个或多个音频服务未运行”如何解决呢?出现这样的情况,我们只需将音频所需服务启动即可。下面跟随小编脚步…

php 两个数组 交集_两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。示例1:输入:nums1 [1,2,2,1], nums2 [2,2]输出:[2,2]示例2:输入:nums1 [4,9,5], nums2 [9,4,9,8,4]输出:[4,9]说明:输出结果中每个…

11纯代码 oc xcode_iOS代码染色原理及技术实践

背景随着业务的迅速发展,业务代码逻辑的复杂度增加。QA测试的质量对于产品上线后的稳定性更加重要。一般QA测试的工作流程分为两大项:自动化测试和人工测试。这两种测试后都需要得到代码覆盖率。自动化测试的覆盖率,在双端都有比较成熟的方案…

删除了几个月的照片能找回么_手机删除照片怎么恢复正常?自动修复,一看就会...

手机删除照片怎么恢复正常?都说鱼的记忆只有七秒钟,那你的记忆是多久呢?曾经手机拍照留念的照片,是否由于一些微不足道的事情,冲动之下删掉了!想要还原删除掉的手机照片,首先要找对照片恢复器:手…

并发测试mysql_Jmeter性能测试系列——结果分析与报告输出

场景运行结束后,需针对测试结果进行性能分析。通常而言,Jmeter性能测试结果分析可从性能测试指标达成方面着手,然后再分析测试过程中出现的异常情况,逐一判断是否存在性能风险。1.用户登陆并发测试结果分析获取测试指标提取阶段获…

怎样取消连续包月自动续费_苹果手机连续包月会员怎么取消 设置iPhone解除应用自动续费...

[闽南网]相信我们都有在用苹果手机下载软件,但是有时候一个不小心就被开通了包月续费,这个的话会长期进行扣费,要是不想开通的话可以进行取消,不知道的话可以查看下面的教程。取消收费项目是可以从电脑端和手机端两个渠道来进行&a…

配置snmp_多种设备基于 SNMP 协议的敏感信息泄露漏洞数据分析报告

作者:知道创宇404实验室1. 更新情况2. 事件概述SNMP协议[1],即简单网络管理协议(SNMP,Simple Network Management Protocol),默认端口为 161/UDP,目前一共有3个版本:V1,V…

建立项目接口文档_分享:一步一个脚印,vue入门之使用mockjs搭建vue项目测试服务器...

在以前的文档中,我们构建了vue项目的整体架构,详见vue入门:vue项目架构设计起步,现在我们主要对其中的mock server 进行完善。一、概述前后端分离的项目优点之一就是可以前后端并行开发,互不影响。那么在后端接口没有完…

单机最大负载_电流互感器允许接入的实际最大二次负载(注电案例1865)

某国外水电站安装的水轮发电机组,单机额定容量为 120MW,发电机额定电压为 13.8kV,cosφ0.85。发电机、主变压器采用发变组单元接线,未装设发电机断路器,主变高压侧三相短路时流过发电机的最大短路电流为 19.6kA。发电机…

html video显示进度条_使用 tqdm 在 Python 应用中显示进度 | Linux 中国

如果你的程序需要一段时间才能显示结果,可通过显示它的进度来避免让用户感到沮丧。来源:https://linux.cn/article-12990-1.html作者:Moshe Zadka译者:geekpi(本文字数:3093,阅读时长大约&#…

课题开题报告范文样本_成都汽车职业技术学校举行 2020年省、市、区课题开题报告会...

01为深入贯彻落实国务院、省、市、区关于深化教育教学改革的重要精神,充分发挥教育科研的先导作用,明晰课题研究的思路并提高课题研究的针对性,1月12日,成都汽车职业技术学校举行2020年省、市、区课题开题报告会。本次开题报告会邀…

安装mysql5 1步骤_Linux系统安装MySQL详细步骤(mysql-5.1等)

第一步、查找以前是否安装有mysql使用下面命令:rpm -qa|grep -i mysql如果显示有包则说明已安装mysql第二步、如果已安装,则需要删除已安装的数据库可按以下步骤删除数据库:删除包命令:rpm -e --nodeps 【包名】rpm -e --nodeps …

mysql分页查询关键_MySQL优化教程之超大分页查询

背景基本上只要是做后台开发,都会接触到分页这个需求或者功能吧。基本上大家都是会用MySQL的LIMIT来处理,而且我现在负责的项目也是这样写的。但是一旦数据量起来了,其实LIMIT的效率会极其的低,这一篇文章就来讲一下LIMIT子句优化…

mysql 分页 jdbc_JDBC调用MySQL分页存储过程实现(一)

DROP PROCEDURE IF EXISTS pro_pager;CREATE DEFINER root% PROCEDURE pro_pager(in p_pageNo int, /*当前页*/in p_perPageCnt int, /*每页记录数*/in p_sql VARCHAR(2000), /*查询sql语句*/out v_totalRowsCnt int, /*记录总条数*/out v_totalPageCnt int) /*记录总页数*/BE…

zabbix proxy mysql_zabbix proxy 配置

在监控大量服务器时,如果将所有的请求都发送到一个zabbix server上,将会对我们的zabbix server造成很大的压力,我们在规划多个区域或机房进行监控的时候,会考虑到使用zabbix proxy 来代理zabbix server 的部分功能。zabbix server…

mvc mysql linq_MVC3+Linq to sql 显示数据库中数据表的数据

1:首先创建asp.net mvc3应用程序 2:创建项目完成后 找到controllers文件鼠标右击选择添加控制器 3 为models文件夹添加一个linq to sql类文件,然后把数据库中的数据库复制进来。如截图操作 4:添加控制器好后会生成一个HomeControl…

mysql工作表格制作教程_Access制作复杂报表

何制作复杂报表利用excel输出复杂报表 在读这篇文章以前首先要提醒大家,Access 本身的报表也具有很强的实用性和强大的功能,只有当你发掘了其本身全部的功能却仍不能满足你对报表的特殊要求时才请使用 Excel 输出报表。很明显,使用 Excel 输出…

php+mysql投票代码_PHP+jQuery+MySql实现红蓝投票功能

本文是一篇综合知识应用类文章,需要您具备PHP、jQuery、MySQL以及html和css方面的基本知识。本文在《PHPMySqljQuery实现的“顶”和“踩”投票功能》一文基础上做了适当改进,共用了数据表,您可以先点击了解这篇文章。HTML我们需要在页面中展示…