日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

sql group by having用法_神奇的 SQL 为什么 GROUP BY 之后不能直接引用原表中的列?...

發布時間:2025/3/12 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sql group by having用法_神奇的 SQL 为什么 GROUP BY 之后不能直接引用原表中的列?... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:青石路

cnblogs.com/youzhibing/p/11516154.html

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_class
GROUP?BY?cno,cname;

可是有人會想了,cno 和 cname 本來就是一對一,cno 一旦確定,cname 也就確定了,那 SQL 是不是可以這么寫 ?

SELECT?cno,cname,count(sno),MAX(sno)?
FROM?tbl_student_class
GROUP?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_mode
SELECT?@@sql_mode;

我們可以看到,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 子句中的列。那如果我們去掉該模式(從“嚴格模式”到“寬松模式”)呢 ?

我們發現,上述報錯的 SQL

--?寬松模式下?可以執行
SELECT?cno,cname,count(sno),MAX(sno)?
FROM?tbl_student_class
GROUP?BY?cno;

能正常執行了,但是一般情況下不推薦這樣配置,線上環境往往是“嚴格模式”,而不是“寬松模式”;雖然案例中,無論是“嚴格模式”,還是“寬松模式”,結果都是對的,那是因為 cno 與 cname 唯一對應的,如果 cno 與 cname 不是唯一對應,那么在“寬松模式下” cname 的值是隨機的,這就會造成難以排查的問題,有興趣的可以去試試。那為什么會有 ONLY_FULL_GROUP_BY 模式呢 ??我們繼續往下看

階(order)是用來區分集合或謂詞的階數的概念。謂詞邏輯中,根據輸入值的階數對謂詞進行分類。

= 或者 BETWEEEN 等輸入值為一行的謂詞叫作"一階謂詞",而像 EXISTS 這樣輸入值為行的集合的謂詞叫作"二階謂詞"(HAVING 的輸入值也是集合,但它不是謂詞)。以此類推,三階謂詞=輸入值為"集合的集合"的謂詞,四階謂詞=輸入值為"集合的集合的集合"的謂詞,但是 SQL 里并不會出現三階以上的情況,所以不用太在意。在Java知音公眾號內回復 面試題聚合 送你一份Java面試題寶典

簡單點如下圖

談到了階,就不得不談下集合論;集合論是 SQL 語言的根基,因為它的這個特性,SQL 也被稱為面向集合語言。只有從集合的角度來思考,才能明白 SQL 的強大威力。通過上圖,相信大家也都能看到,這里不做更深入的講解了,有興趣的可以去查相關資料。

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

很多人都知道聚合查詢的限制,但是很少有人能正確地理解為什么會有這樣的約束。表 tbl_student_class 中的 cname 存儲的是每位學生的班級信息。

但需要注意的是,這里的 cname 只是每個學生的屬性,并不是小組的屬性,而 GROUP BY 又是聚合操作,操作的對象就是由多個學生組成的小組,因此,小組的屬性只能是平均或者總和等統計性質的屬性,如下圖

詢問每個學生的 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進階教程》

END

Java面試題專欄

【61期】MySQL行鎖和表鎖的含義及區別(MySQL面試第四彈)【62期】解釋一下MySQL中內連接,外連接等的區別(MySQL面試第五彈)【63期】談談MySQL 索引,B+樹原理,以及建索引的幾大原則(MySQL面試第六彈)【64期】MySQL 服務占用cpu 100%,如何排查問題? (MySQL面試第七彈)【65期】Spring的IOC是啥?有什么好處?【66期】Java容器面試題:談談你對 HashMap 的理解【67期】談談ConcurrentHashMap是如何保證線程安全的?【68期】面試官:對并發熟悉嗎?說說Synchronized及實現原理【69期】面試官:對并發熟悉嗎?談談線程間的協作(wait/notify/sleep/yield/join)【70期】面試官:對并發熟悉嗎?談談對volatile的使用及其原理

我知道你 “在看

總結

以上是生活随笔為你收集整理的sql group by having用法_神奇的 SQL 为什么 GROUP BY 之后不能直接引用原表中的列?...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文字幕日韩在线观看 | 国产中文字幕乱人伦在线观看 | 亚洲国产第一区 | 台湾黄色网址 | 国产精品美女www爽爽爽视频 | 小柔的淫辱日记(1~7) | 久久久www成人免费无遮挡大片 | 成人免费短视频 | www.国产欧美 | 国产美女视频 | 一二三av | 日韩激情一区二区三区 | 在线视频麻豆 | 久久视频免费在线观看 | 国产午夜啪啪 | 成人福利免费视频 | 国产伦理一区 | 毛片入口| 中文天堂网 | 人妻少妇精品一区二区三区 | 伊人亚洲影院 | 欧美黄色免费观看 | 97视频人人 | 亚洲大胆| 国产一区视频在线免费观看 | 欧洲精品在线播放 | 成年人免费网站 | 亚洲欧美日韩天堂 | 亚洲日本欧美精品 | 91九色中文 | 亚洲 高清 成人 动漫 | 精品一区二区三区免费看 | 国产欧美专区 | 97av视频 | 激情福利社 | 国产一区二区视频免费 | 欧美激情亚洲 | 国产精品一区二区免费在线观看 | 黄色国产在线观看 | 亚洲欧美日韩动漫 | 欧美性生交xxxxx | 婷婷爱五月 | 一区二区日本 | 国产在线精品成人欧美 | 光棍天堂av | bbbbbxxxxx性欧美 | 国产资源站 | 四虎成人在线观看 | 国产一区影院 | 91麻豆国产精品 | 韩国主播青草55部完整 | 国产 第1190页| 亚洲av无码国产综合专区 | 欧美亚一区二区三区 | 网站在线观看你懂的 | 国产一级影院 | 福利一区二区 | 欧美又大又硬又粗bbbbb | 色窝窝无码一区二区三区成人网站 | 日韩av在线天堂 | 国产精品污www一区二区三区 | www.伊人久久 | 国模视频一区二区 | 欧美性受xxxx黑人猛交88 | 欧美日韩国产不卡 | 女生隐私免费看 | 日韩欧美在线一区二区 | 久色视频在线观看 | 青娱乐在线视频免费观看 | 亚洲天堂一区在线 | 蜜桃视频污在线观看 | 久久久久久久亚洲精品 | 人妻丰满熟妇岳av无码区hd | 在线观看av国产一区二区 | 中国大陆一级毛片 | 日日干日日爽 | 人妻无码一区二区三区久久99 | 九九色播| av电影在线观看网址 | 久久毛片视频 | 免费看欧美成人a片无码 | 天天色图片 | 中文字幕观看在线 | 久久人人精品 | 我们的2018中文免费看 | 中文亚洲字幕 | 欧美性久久 | 国产成人免费视频网站 | www.色哟哟| 99re在线视频精品 | 欧美一区二区三区激情视频 | 国产精品综合视频 | 欧美成人精品一区二区三区在线观看 | 久久免费播放视频 | 亚洲三级在线免费观看 | 人人射影院 | 色不卡 | 亚洲AV无码精品自拍 | 亚洲美女性视频 |