成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

神奇的SQL之層級→為什么GROUPBY之后不能直接引用原表中的列

GROUP BY 后 SELECT 列的限制

標(biāo)準(zhǔn) SQL 規(guī)定,在對表進(jìn)行聚合查詢的時候,只能在 SELECT 子句中寫下面 3 種內(nèi)容:通過 GROUP BY 子句指定的聚合鍵、聚合函數(shù)(SUM 、AVG 等)、常量。我們來看個例子

創(chuàng)新互聯(lián)專注于合江網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供合江營銷型網(wǎng)站建設(shè),合江網(wǎng)站制作、合江網(wǎng)頁設(shè)計、合江網(wǎng)站官網(wǎng)定制、微信小程序服務(wù),打造合江網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供合江網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

我們有 學(xué)生班級表(tbl_student_class) 以及 數(shù)據(jù)如下 :

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?'學(xué)號',
?cno?varchar(5)?NOT?NULL?COMMENT?'班級號',
?cname?varchar(20)?NOT?NULL?COMMENT?'班級名',
?PRIMARY?KEY?(id)
)?COMMENT='學(xué)生班級表';
--?----------------------------
--?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班');

我們想統(tǒng)計各個班(班級號、班級名)一個有多少人、以及最大的學(xué)號,我們該怎么寫這個查詢 SQL ? 我想大家應(yīng)該都會

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;

執(zhí)行報錯了:

[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 列表中的第二個表達(dá)式(cname)不在 GROUP BY 的子句中,同時它也不是聚合函數(shù);這與 sql 模式:ONLY_FULL_GROUP_BY 不相容。

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

SQL 模式

MySQL 服務(wù)器可以在不同的 SQL 模式下運行,并且可以針對不同的客戶端以不同的方式應(yīng)用這些模式,具體取決于 sql_mode 系統(tǒng)變量的值。 DBA 可以設(shè)置全局SQL模式以匹配站點服務(wù)器操作要求,并且每個應(yīng)用程序可以將其會話 SQL 模式設(shè)置為其自己的要求。模式會影響 MySQL 支持的 SQL 語法以及它執(zhí)行的 數(shù)據(jù)驗證檢查,這使得在不同環(huán)境中使用MySQL以及將MySQL與其他數(shù)據(jù)庫服務(wù)器一起使用變得更加容易。更多詳情請查閱官網(wǎng):Server SQL Modes。MySQL 版本不同,內(nèi)容會略有不同(包括默認(rèn)值),查閱的時候注意與自身的 MySQL 版本保持一致。

SQL 模式主要分兩類:語法支持類和數(shù)據(jù)檢查類,常用的如下

語法支持類

ONLY_FULL_GROUP_BY

對于 GROUP BY 聚合操作,如果在 SELECT 中的列、HAVING 或者 ORDER BY 子句的列,沒有在GROUP BY中出現(xiàn),那么這個SQL是不合法的

ANSI_QUOTES

啟用 ANSI_QUOTES 后,不能用雙引號來引用字符串,因為它被解釋為識別符,作用與 ` 一樣。設(shè)置它以后,update t set f1="" ...,會報 Unknown column ‘’ in field list 這樣的語法錯誤

PIPES_AS_CONCAT

將 || 視為字符串的連接操作符而非 或 運算符,這和Oracle數(shù)據(jù)庫是一樣的,也和字符串的拼接函數(shù) CONCAT() 相類似

NO_TABLE_OPTIONS

使用 SHOW CREATE TABLE 時不會輸出MySQL特有的語法部分,如 ENGINE ,這個在使用 mysqldump 跨DB種類遷移的時候需要考慮

NO_AUTO_CREATE_USER

字面意思不自動創(chuàng)建用戶。在給MySQL用戶授權(quán)時,我們習(xí)慣使用 GRANT ... ON ... TO dbuser 順道一起創(chuàng)建用戶。設(shè)置該選項后就與oracle操作類似,授權(quán)之前必須先建立用戶

數(shù)據(jù)檢查類

NO_ZERO_DATE

認(rèn)為日期 ‘0000-00-00’ 非法,與是否設(shè)置后面的嚴(yán)格模式有關(guān)

1、如果設(shè)置了嚴(yán)格模式,則 NO_ZERO_DATE 自然滿足。但如果是 INSERT IGNORE 或 UPDATE IGNORE,’0000-00-00’依然允許且只顯示warning;

2、如果在非嚴(yán)格模式下,設(shè)置了NO_ZERO_DATE,效果與上面一樣,’0000-00-00’ 允許但顯示warning;如果沒有設(shè)置NO_ZERO_DATE,no warning,當(dāng)做完全合法的值;

3、NO_ZERO_IN_DATE情況與上面類似,不同的是控制日期和天,是否可為 0 ,即 2010-01-00 是否合法;

NO_ENGINE_SUBSTITUTION

使用 ALTER TABLE 或 CREATE TABLE 指定 ENGINE 時, 需要的存儲引擎被禁用或未編譯,該如何處理。啟用 NO_ENGINE_SUBSTITUTION 時,那么直接拋出錯誤;不設(shè)置此值時,CREATE用默認(rèn)的存儲引擎替代,ATLER不進(jìn)行更改,并拋出一個 warning

STRICT_TRANS_TABLES

設(shè)置它,表示啟用嚴(yán)格模式。注意 STRICT_TRANS_TABLES 不是幾種策略的組合,單獨指 INSERT、UPDATE 出現(xiàn)少值或無效值該如何處理:

1、前面提到的把 ‘’ 傳給int,嚴(yán)格模式下非法,若啟用非嚴(yán)格模式則變成 0,產(chǎn)生一個warning;

2、Out Of Range,變成插入最大邊界值;

3、當(dāng)要插入的新行中,不包含其定義中沒有顯式DEFAULT子句的非NULL列的值時,該列缺少值;

默認(rèn)模式

當(dāng)我們沒有修改配置文件的情況下,MySQL 是有自己的默認(rèn)模式的;版本不同,默認(rèn)模式也不同

--?查看?MySQL?版本
SELECT?VERSION();
--?查看?sql_mode
SELECT?@@sql_mode;

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

我們可以看到,5.7.21 的默認(rèn)模式包含:

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 就會約束:當(dāng)我們進(jìn)行聚合查詢的時候,SELECT 的列不能直接包含非 GROUP BY 子句中的列。那如果我們?nèi)サ粼撃J剑◤摹皣?yán)格模式”到“寬松模式”)呢 ?

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

我們發(fā)現(xiàn),上述報錯的 SQL

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

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

階(order)是用來區(qū)分集合或謂詞的階數(shù)的概念。謂詞邏輯中,根據(jù)輸入值的階數(shù)對謂詞進(jìn)行分類。= 或者 BETWEEEN 等輸入值為一行的謂詞叫作"一階謂詞",而像 EXISTS 這樣輸入值為行的集合的謂詞叫作"二階謂詞"(HAVING 的輸入值也是集合,但它不是謂詞)。以此類推,三階謂詞=輸入值為"集合的集合"的謂詞,四階謂詞=輸入值為"集合的集合的集合"的謂詞,但是 SQL 里并不會出現(xiàn)三階

以上的情況,所以不用太在意。簡單點如下圖

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

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

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

很多人都知道聚合查詢的限制,但是很少有人能正確地理解為什么會有這樣的約束。表 tbl_student_class 中的 cname 存儲的是每位學(xué)生的班級信息,但需要注意的是,這里的 cname 只是每個學(xué)生的屬性,并不是小組的屬性,而 GROUP BY 又是聚合操作,操作的對象就是由多個學(xué)生組成的小組,因此,小組的屬性只能是平均或者總和等統(tǒng)計性質(zhì)的屬性,如下圖

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

詢問每個學(xué)生的 cname 是可以的,但是詢問由多個學(xué)生組成的小組的 cname 就沒有意義了。對于小組來說,只有"一共多少學(xué)生"或者"最大學(xué)號是多少?"這樣的問法才是有意義的。強行將適用于個體的屬性套用于團(tuán)體之上,純粹是一種分類錯誤;而 GROUP BY 的作用是將一個個元素劃分成若干個子集,使用 GROUP BY 聚合之后,SQL 的操作對象便由 0 階的"行"變?yōu)榱?1 階的"行的集合",此時,行的屬性便不能使用了。SQL 的世界其實是層級分明的等級社會,將低階概念的屬性用在高階概念上會導(dǎo)致秩序的混亂,這是不允許的。此時我相信大家都明白:為什么聚合后不能再引用原表中的列 。

單元素集合也是集合

現(xiàn)在的集合論認(rèn)為單元素集合是一種正常的集合。單元素集合和空集一樣,主要是為了保持理論的完整性而定義的。因此對于以集合論為基礎(chǔ)的 SQL 來說,當(dāng)然也需要嚴(yán)格地區(qū)分元素和單元素集合。因此,元素 a 和集合 {a} 之間存在著非常醒目的層級差別。

a?≠?{a}

這兩個層級的區(qū)別分別對應(yīng)著 SQL 中的 WHERE 子句和 HAVING 子句的區(qū)別。WHERE 子句用于處理"行"這種 0 階的對象,而 HAVING 子句用來處理"集合"這種 1 階的對象。

總結(jié)

1、SQL 嚴(yán)格區(qū)分層級,包括謂詞邏輯中的層級(EXISTS),也包括集合論中的層級(GROUP BY);

2、有了層級區(qū)分,那么適用于個體上的屬性就不適用于團(tuán)體了,這也就是為什么聚合查詢的 SELECT 子句中不能直接引用原表中的列的原因;

3、一般來說,單元素集合的屬性和其唯一元素的屬性是一樣的。這種只包含一個元素的集合讓人覺得似乎沒有必要特意地當(dāng)成集合來看待,但是為了保持理論的完整性,我們還是要嚴(yán)格區(qū)分元素和單元素集合;

點擊獲取?附送學(xué)習(xí)進(jìn)階架構(gòu)資料、PDF書籍文檔、面試資料

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

神奇的SQL之層級 →為什么 GROUP BY 之后不能直接引用原表中的列

網(wǎng)頁名稱:神奇的SQL之層級→為什么GROUPBY之后不能直接引用原表中的列
網(wǎng)站網(wǎng)址:http://jinyejixie.com/article46/ijgieg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、品牌網(wǎng)站設(shè)計微信小程序、外貿(mào)建站營銷型網(wǎng)站建設(shè)、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
昌平区| 勃利县| 偏关县| 曲靖市| 绍兴县| 克东县| 沽源县| 乌兰察布市| 宁化县| 抚松县| 海原县| 曲靖市| 洮南市| 宜州市| 安图县| 忻城县| 清河县| 宣城市| 宾川县| 义乌市| 长沙县| 达州市| 新宾| 嘉善县| 会东县| 唐山市| 宝应县| 保靖县| 平果县| 贺州市| 郴州市| 南雄市| 平利县| 华容县| 获嘉县| 永康市| 会昌县| 辛集市| 察雅县| 连江县| 乐安县|