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.pswp.cn/news/529576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/529576.shtml
英文地址,請注明出處:http://en.pswp.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…

oracle 空閑連接數_oracle數據庫空閑連接

RMAN-04006: error from auxiliary database: ORA-01034: ORACLE not available在使用rman duplicate復制standby數據庫的時候,由于standby數據庫實例必須處于非mount狀態,所以主數據庫直接連接是會報錯的,需要在standby數據庫服務上的監聽器…

配置snmp_多種設備基于 SNMP 協議的敏感信息泄露漏洞數據分析報告

作者:知道創宇404實驗室1. 更新情況2. 事件概述SNMP協議[1],即簡單網絡管理協議(SNMP,Simple Network Management Protocol),默認端口為 161/UDP,目前一共有3個版本:V1,V…

python 個人所得稅問題_Python實現的個人所得稅計算器

這篇文章主要介紹了Python實現的個人所得稅計算器,涉及Python條件判斷與數值運算相關操作技巧,需要的朋友可以參考下本文實例講述了Python實現的個人所得稅計算器。分享給大家供大家參考,具體如下:# -*- coding: utf-8 -*-"""Created on …

建立項目接口文檔_分享:一步一個腳印,vue入門之使用mockjs搭建vue項目測試服務器...

在以前的文檔中,我們構建了vue項目的整體架構,詳見vue入門:vue項目架構設計起步,現在我們主要對其中的mock server 進行完善。一、概述前后端分離的項目優點之一就是可以前后端并行開發,互不影響。那么在后端接口沒有完…

有效字符區域 獲取textview_Android編程開發之TextView文字顯示和修改方法(附TextView屬性介紹)...

本文實例講述了Android編程開發之TextView文字顯示和修改方法。分享給大家供大家參考,具體如下:一. 新建一個Activity 和 Layout首先在layout文件夾中新建一個activity_main.xml,在新建工程的時候一般默認會新建此xml文件,修改其代碼如下:activity_main.…

單機最大負載_電流互感器允許接入的實際最大二次負載(注電案例1865)

某國外水電站安裝的水輪發電機組,單機額定容量為 120MW,發電機額定電壓為 13.8kV,cosφ0.85。發電機、主變壓器采用發變組單元接線,未裝設發電機斷路器,主變高壓側三相短路時流過發電機的最大短路電流為 19.6kA。發電機…

vue怎么vw布局好用_vue cli3項目的pc自適應布局_vw

前言vw布局的頁面是等比改變的,比如我們在一個750px的屏幕寬度中使用了vw,當我們把屏幕寬度改為1920的時候,網頁的整個樣式包括字體都會等比放大.vw布局我用于大屏監控數據展示.下圖是750屏幕寬度下的頁面下圖是1920屏幕寬度下的頁面pc端配置1.安裝postcss-px-to-viewport插件,…

python做得怎么變成exe_Python如何生成exe文件?

背景圖來源:click斗魚直播間真實rtmp地址獲取(含工具類下載)?zhuanlan.zhihu.com最經典的Python爬蟲(圖片)案例?zhuanlan.zhihu.com寫在前面:之前用python生成過可執行的exe文件(斗魚推流地址exe ,圖片exe,芳兒小團子千人成像ex…

python mkl freebsd_freebsd下之簡單安裝python

先su到root帳戶進入/usr/ports/lang/python26然后直接make整個過程如圖所示,經過漫長的編譯之后...然后make install又是漫長的等待...出現Install them as needed.--------------------------------------------------------This package was built with the exper…

html video顯示進度條_使用 tqdm 在 Python 應用中顯示進度 | Linux 中國

如果你的程序需要一段時間才能顯示結果,可通過顯示它的進度來避免讓用戶感到沮喪。來源:https://linux.cn/article-12990-1.html作者:Moshe Zadka譯者:geekpi(本文字數:3093,閱讀時長大約&#…

課題開題報告范文樣本_成都汽車職業技術學校舉行 2020年省、市、區課題開題報告會...

01為深入貫徹落實國務院、省、市、區關于深化教育教學改革的重要精神,充分發揮教育科研的先導作用,明晰課題研究的思路并提高課題研究的針對性,1月12日,成都汽車職業技術學校舉行2020年省、市、區課題開題報告會。本次開題報告會邀…

vsftp日志查看_vsftp日志xferlog格式分析(示例代碼)

1、開始vsftp記錄日志。修改/etc/vsftpd/vsftpd.conf 如下:xferlog_enableYESxferlog_std_formatYESxferlog_file/var/log/xferlogFTP服務器的日志設置,可以通過修改主配置文件/etc/vsftpd.conf實現。主配置文件中與日志設置有關的選項包括xferlog_enabl…