SELECT执行过程,MySQL聚合函数,多行分组函数,GROUP BY HAVING,详细完整可收藏
文章目錄
- 1、聚合函數(shù)介紹
- 2、五個(gè)常用聚合函數(shù)
- 3、GROUP BY
- 4、HAVING
- 5、SELECT的執(zhí)行過程
1、聚合函數(shù)介紹
聚合函數(shù)作用于一組數(shù)據(jù),并對一組數(shù)據(jù)返回一個(gè)值。聚合函數(shù)不能嵌套調(diào)用。比如不能出現(xiàn)類似“AVG(SUM(字段名稱))”形式的調(diào)用。
2、五個(gè)常用聚合函數(shù)
2.1 AVG和SUM函數(shù)
可以對數(shù)值型數(shù)據(jù)使用AVG(取平均)和SUM(求和)函數(shù)。(忽略NULL值行)
2.2 MIN和MAX函數(shù)
可以對任意數(shù)據(jù)類型的數(shù)據(jù)使用 MIN 和 MAX 函數(shù)。
2.3 COUNT函數(shù)
COUNT(*)返回表中記錄總數(shù),適用于任意數(shù)據(jù)類型。
COUNT(expr) 返回expr不為空的記錄總數(shù)。
SELECT COUNT(commission_pct) FROM employees WHERE department_id = 50;問題:用count(*),count(1),count(列名)誰好呢?
其實(shí),對于MyISAM引擎的表是沒有區(qū)別的。這種引擎內(nèi)部有一計(jì)數(shù)器在維護(hù)著行數(shù)。Innodb引擎的表用count(*),count(1)直接讀行數(shù),復(fù)雜度是O(n),因?yàn)閕nnodb真的要去數(shù)一遍。但好于具體的count(列名)。
問題:能不能使用count(列名)替換count(*)?
不要使用 count(列名)來替代 count() , count() 是 SQL92 定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語法,跟數(shù)據(jù)庫無關(guān),跟 NULL 和非 NULL 無關(guān)。
說明:count(*)會(huì)統(tǒng)計(jì)值為 NULL 的行,而 count(列名)不會(huì)統(tǒng)計(jì)此列為 NULL 值的行。
3、GROUP BY
3.1 基本使用
可以使用GROUP BY子句將表中的數(shù)據(jù)分成若干組
明確:WHERE一定放在FROM后面
在SELECT列表中所有未包含在組函數(shù)中的列都應(yīng)該包含在 GROUP BY子句中
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id ;3.2 使用多個(gè)列分組
3.3 GROUP BY中使用WITH ROLLUP
使用 WITH ROLLUP 關(guān)鍵字之后,在所有查詢出的分組記錄之后增加一條記錄,該記錄計(jì)算查詢出的所有記錄的總和,即統(tǒng)計(jì)記錄數(shù)量。
注意:
當(dāng)使用ROLLUP時(shí),不能同時(shí)使用ORDER BY子句進(jìn)行結(jié)果排序,即ROLLUP和ORDER BY是互相排斥的。
4、HAVING
4.1 基本使用
過濾分組:HAVING子句
①行已經(jīng)被分組。
②使用了聚合函數(shù)。
③滿足HAVING 子句中條件的分組將被顯示。
④HAVING 不能單獨(dú)使用,必須要跟 GROUP BY 一起使用。
非法使用聚合函數(shù) :不能在 WHERE 子句中使用聚合函數(shù)。
4.2 WHERE和HAVING的對比
區(qū)別1:WHERE 可以直接使用表中的字段作為篩選條件,但不能使用分組中的計(jì)算函數(shù)作為篩選條件;HAVING 必須要與 GROUP BY 配合使用,可以把分組計(jì)算的函數(shù)和分組字段作為篩選條件。這決定了,在需要對數(shù)據(jù)進(jìn)行分組統(tǒng)計(jì)的時(shí)候,HAVING 可以完成 WHERE 不能完成的任務(wù)。這是因?yàn)?#xff0c;在查詢語法結(jié)構(gòu)中,WHERE 在 GROUP BY 之前,所以無法對分組結(jié)果進(jìn)行篩選。HAVING 在 GROUP BY 之后,可以使用分組字段和分組中的計(jì)算函數(shù),對分組的結(jié)果集進(jìn)行篩選,這個(gè)功能是 WHERE 無法完成的。另外,WHERE排除的記錄不再包括在分組中。
區(qū)別2:如果需要通過連接從關(guān)聯(lián)表中獲取需要的數(shù)據(jù),WHERE 是先篩選后連接,而 HAVING 是先連接后篩選。 這一點(diǎn),就決定了在關(guān)聯(lián)查詢中,WHERE 比 HAVING 更高效。因?yàn)?WHERE 可以先篩選,用一個(gè)篩選后的較小數(shù)據(jù)集和關(guān)聯(lián)表進(jìn)行連接,這樣占用的資源比較少,執(zhí)行效率也比較高。HAVING 則需要先把結(jié)果集準(zhǔn)備好,也就是用未被篩選的數(shù)據(jù)集進(jìn)行關(guān)聯(lián),然后對這個(gè)大的數(shù)據(jù)集進(jìn)行篩選,這樣占用的資源就比較多,執(zhí)行效率也較低。
開發(fā)中的選擇:
WHERE 和 HAVING 也不是互相排斥的,我們可以在一個(gè)查詢里面同時(shí)使用 WHERE 和 HAVING。包含分組統(tǒng)計(jì)函數(shù)的條件用 HAVING,普通條件用 WHERE。這樣,我們就既利用了 WHERE 條件的高效快速,又發(fā)揮了 HAVING 可以使用包含分組統(tǒng)計(jì)函數(shù)的查詢條件的優(yōu)點(diǎn)。當(dāng)數(shù)據(jù)量特別大的時(shí)候,運(yùn)行效率會(huì)有很大的差別。
5、SELECT的執(zhí)行過程
5.1 查詢的結(jié)構(gòu)
#方式1: SELECT ...,....,... FROM ...,...,.... WHERE 多表的連接條件 AND 不包含組函數(shù)的過濾條件 GROUP BY ...,... HAVING 包含組函數(shù)的過濾條件 ORDER BY ... ASC/DESC LIMIT ...,... #方式2: SELECT ...,....,... FROM ... JOIN ... ON 多表的連接條件 JOIN ... ON ... WHERE 不包含組函數(shù)的過濾條件 AND/OR 不包含組函數(shù)的過濾條件 GROUP BY ...,... HAVING 包含組函數(shù)的過濾條件 ORDER BY ... ASC/DESC LIMIT ...,... #其中: #(1)from:從哪些表中篩選 #(2)on:關(guān)聯(lián)多表查詢時(shí),去除笛卡爾積 #(3)where:從表中篩選的條件 #(4)group by:分組依據(jù) #(5)having:在統(tǒng)計(jì)結(jié)果中再次篩選 #(6)order by:排序 #(7)limit:分頁5.2 SELECT執(zhí)行順序
①關(guān)鍵字的順序是不能顛倒的:
②SELECT 語句的執(zhí)行順序:
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT SELECT DISTINCT player_id, player_name, count(*) as num # 順序 5 FROM player JOIN team ON player.team_id = team.team_id # 順序 1 WHERE height > 1.80 # 順序 2 GROUP BY player.team_id # 順序 3 HAVING num > 2 # 順序 4 ORDER BY num DESC # 順序 6 LIMIT 2 # 順序 7在 SELECT 語句執(zhí)行這些步驟的時(shí)候,每個(gè)步驟都會(huì)產(chǎn)生一個(gè) 虛擬表 ,然后將這個(gè)虛擬表傳入下一個(gè)步驟中作為輸入。需要注意的是,這些步驟隱含在 SQL 的執(zhí)行過程中,對于我們來說是不可見的。
5.3 SQL 的執(zhí)行原理
SELECT 是先執(zhí)行 FROM 這一步的。在這個(gè)階段,如果是多張表聯(lián)查,還會(huì)經(jīng)歷下面的幾個(gè)步驟:
①首先先通過 CROSS JOIN 求笛卡爾積,相當(dāng)于得到虛擬表 vt(virtualtable)1-1;
②通過 ON 進(jìn)行篩選,在虛擬表 vt1-1 的基礎(chǔ)上進(jìn)行篩選,得到虛擬表 vt1-2;
③添加外部行。如果我們使用的是左連接、右鏈接或者全連接,就會(huì)涉及到外部行,也就是在虛擬表 vt1-2 的基礎(chǔ)上增加外部行,得到虛擬表 vt1-3。
當(dāng)然如果我們操作的是兩張以上的表,還會(huì)重復(fù)上面的步驟,直到所有表都被處理完為止。這個(gè)過程得到是我們的原始數(shù)據(jù)。當(dāng)我們拿到了查詢數(shù)據(jù)表的原始數(shù)據(jù),也就是最終的虛擬表 vt1 ,就可以在此基礎(chǔ)上再進(jìn)行 WHERE 階段 。在這個(gè)階段中,會(huì)根據(jù) vt1 表的結(jié)果進(jìn)行篩選過濾,得到虛擬表 vt2 。然后進(jìn)入第三步和第四步,也就是 GROUP 和 HAVING 階段 。在這個(gè)階段中,實(shí)際上是在虛擬表 vt2 的基礎(chǔ)上進(jìn)行分組和分組過濾,得到中間的虛擬表 vt3 和 vt4 。當(dāng)我們完成了條件篩選部分之后,就可以篩選表中提取的字段,也就是進(jìn)入到 SELECT 和 DISTINCT階段 。首先在 SELECT 階段會(huì)提取想要的字段,然后在 DISTINCT 階段過濾掉重復(fù)的行,分別得到中間的虛擬表vt5-1 和 vt5-2 。當(dāng)我們提取了想要的字段數(shù)據(jù)之后,就可以按照指定的字段進(jìn)行排序,也就是ORDER BY階段 ,得到虛擬表vt6。最后在 vt6 的基礎(chǔ)上,取出指定行的記錄,也就是 LIMIT 階段 ,得到最終的結(jié)果,對應(yīng)的是虛擬表vt7 。當(dāng)然我們在寫 SELECT 語句的時(shí)候,不一定存在所有的關(guān)鍵字,相應(yīng)的階段就會(huì)省略。
總結(jié)
以上是生活随笔為你收集整理的SELECT执行过程,MySQL聚合函数,多行分组函数,GROUP BY HAVING,详细完整可收藏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL排序ORDER BY与分页LI
- 下一篇: 嵌套套娃,MySQL子查询,单行与多行子