SqlServer:分組查詢和聚集函數


聚集函數

聚合函數是用於對表進行記錄統計、數據運算的函數,它返回單個值。聚合函數經常與 SELECT 語句的 GROUP BY 子句一起使用,作為分組依據。聚合函數主要有 COUNT(求記錄數)、SUM(求和)、AVG(求平均值)、MAX(求最大值)、MIN (求最小值) 5 個。

常用的函數

如下是 5 個常用的聚集函數,這些函數在統計時系統會自動忽略 NULL 值。

聚集函數 功能 格式 數據類型
count 求符合條件的記錄數 count(列名) 或者 count(DISTINCT 列名)
MAX 求某一列的最大值 MAX(列名) 列的類型可以比較大小
MIN 求某一列的最小值 MIN(列名) 列的類型可以比較大小
AVG 求某一列的平均值 AVG(列名) 列的類型只能是數值型或者貨幣型
SUM 求某一列的總和 SUM(列名) 列的類型只能是數值型或者貨幣型

查詢樣例

假設此時有成績表 Score,表中具有以下字段和記錄。

樣例一

查詢選課表中最高分、平均分、最低分,需要使用 MAX、MIN、AVG 3 個聚集函數。

SELECT MAX(DEGREE), AVG(DEGREE), MIN(DEGREE)
FROM Score

樣例二

查詢“3-105”課程的最高分、平均分和最小成績,在上一個樣例的基礎上使用 WHERE 子句進行過濾。

SELECT MAX(DEGREE), AVG(DEGREE), MIN(DEGREE)
FROM Score
WHERE CNO = '3-105'

分組查詢

GROUP BY 子句

利用 SELECT 的 GROUP BY 子句,能夠對查詢結果按照指定的字段進行分組,值相等的記錄被分在同一組。GROUP BY 子句往往和 SQL 的聚合函數一起使用,基本格式如下,其中 GROUP BY 后面的列名稱為分組依據,根據這個字段的不同值進行分組顯示。

SELECT 列名列表
FROM 表名
WHERE 條件
GROUP BY 列名

如果有 GROUP BY 子句,則在 SELECT 后面的列名必須包含在聚合函數中,或者包含在 GROUP BY 子句中,否則系統拒絕執行。

HAVING 子句

如果 SELECT 語句中有 GROUP BY 子句,但是想對匯總查詢進行過濾不能使用 WHERE 子句。此時可以使用 HAVING 子句對 GROUP BY 進行限制,對不符合要求的進行過濾分組。HAVING 子句的格式如下,HAVING 子句必須和 GROUP BY 子句配合,且放在 GROUP BY 子句的后面表示分組的前提條件。

HAVING(條件)

HAVING 子句和 WHERE 子句的區別在於作用對象不同,WHERE 子句的作用對象是表,是從表中選擇出滿足篩選條件的記錄,而 HAVING 子句的作用對象是組,是從組中選擇出滿足篩選條件的記錄。

查詢樣例

樣例一

查詢各學生的選課數,此時可以對學號 Sno 進行分組,用 Count 函數統計每組有多少記錄。

SELECT SNO,COUNT(*)
FROM Score
GROUP BY SNO

樣例二

查詢選修了3 門以上課程的學生學號,此時需要使用 HAVING 子句對分組進行過濾。

SELECT SNO, COUNT(*)
FROM Score
GROUP BY SNO
HAVING COUNT(*) >= 3

樣例三

按學號分組匯總學生的平均分,並按平均分的降序排列,分組后使用 AVG 函數進行聚集,同時用 ORDER BY 子句進行排序。

SELECT SNO 學號, AVG(DEGREE) 平均分
FROM Score
GROUP BY SNO
ORDER BY 平均分 DESC

樣例四

假設 Student 表中有如下一些數據:

查詢每位學生的最高、最低分、平均分,包括學號、姓名、最高、最低分和平均分,在上述樣例的基礎上使用 JOIN 子句進行多表查詢。注意在 SELECT 后面的列名必須包含在聚合函數中,或者包含在 GROUP BY 子句中,否則系統拒絕執行,因此 GROUP BY 子句中需要給出 Sno 和 Sname 2 個字段。

SELECT S.SNO, SNAME, MAX(DEGREE) 最高分, MIN(DEGREE) 最低分, AVG(DEGREE) 平均分
FROM Score SC
JOIN Student S ON S.SNO = SC.SNO
GROUP BY S.SNO, SNAME

生成匯總值

使用 GROUP BY 子句進行匯總以后,可以使用一些運算符生成匯總值,例如對各個字段聚合的分組輸出一個總的匯總信息。

ROLLUP 運算符

使用 GROUP BY 子句和 ROLLUP 操作符時,將在結果集中增加一行顯示總和或平均值之類的匯總值。處理 GROUP BY 中字段列表的順序是從右到左,然后對每個組使用聚合函數,新增的行以 NULL 標識。
注意不能同時使用關鍵字 ALL 和操作符 ROLLUP,使用 ROLLUP 時要確保出現在 GROUP BY 后的各字段,在數據庫環境中具有確定的、有意義的關系。

CUBE 運算符

使用 GROUP BY 子句和 CUBE 操作符,能生成基於 GROUP BY 子句指定的所有字段的可能組合。如果在 GROUP BY 子句中有 n 個字段或表達式,則在結果集中將返回 2^n 種可能的組合,結果集中含有 NULL 的記錄代表該記錄由 CUBE 操作符生成。
注意不能同時使用關鍵字 ALL 和操作符 CUBE,使用 CUBE 時要確保出現在 GROUP BY 后的各字段,在數據庫環境中具有確定的、有意義的關系。

GROUPING 函數

GROUPING 函數能夠幫助識別結果集中的空值是表中原有的空值,還是由 ROLLUP 或 CUBE 生成的含有匯總值的新記錄。GROUPING 函數指定字段后將生成一個新的字段,如果該字段返回 1,代表結果集中的這一記錄是由 ROLLUP 或 CUBE 生成的,否則該記錄原本就存在於數據庫的表中。

查詢樣例

樣例一

查詢學生信息,包括學號、課程號、成績以及學生的平均分。此時需要使用 ROLLUP 函數指定需要聚集的列,生成一則匯總信息。

SELECT isnull(CAST(Sno as char(8)), '總平均分') Sno,    
        --若該數據為所有分組的匯總數據,用“總平均分”替換 NULL
	CASE WHEN Sno is null AND Cno IS null THEN '' ELSE isnull(CAST(CNO as char(6)), '平均分') END CNO,
        --若該數據為某個分組的匯總數據,用“平均分”替換 NULL
	AVG(Degree)
FROM Score
GROUP BY GROUPING SETS (ROLLUP(Sno, Cno))

樣例二

查詢學生信息,包括姓名、課程名、成績以及每位學生的平均分和每門課程的平均分。由於還需要對每門課程生成匯總記錄,因此需要使用操作符 CUBE 生成多個匯總信息。

SELECT CASE WHEN S.Sname is null AND Cno IS null THEN '總平均分' ELSE isnull(CAST(Sname as char(10)), '課程平均分') END Sname,
       --總匯總數據用“總平均分”替換 NULL,Cno 字段匯總數據用“課程平均分”替換 NULL
       CASE WHEN Sname is null AND Cno IS null THEN '' ELSE isnull(CAST(Cno as char(10)), '學生平均分') END Cno,
       --若該數據為某個分組的匯總數據,匯總數據用“學生平均分”替換 NULL
       AVG(Degree) 成績
FROM Score SC
JOIN Student S ON S.Sno = SC.Sno
GROUP BY Sname, Cno WITH CUBE

樣例三

假設此時有成績表 Course,表中具有以下字段和記錄。

查詢學生信息,包括學號、姓名、課程號、課程名、成績以及每位學生的平均分和每門課程的平均分。此時由於需要生成多個匯總數據,需要使用 GROUPING SETS 函數指定需要匯總的數據。

SELECT 
    CASE WHEN SC.Sno IS null AND SC.Cno IS null THEN '總' ELSE isnull(CAST(SC.Sno as char(10)), '課程') END Sno,
    CASE WHEN SC.Sno IS null AND SC.Cno IS null THEN '平均分' ELSE isnull(CAST(S.Sname as char(10)), '平均分') END Sname,
    CASE WHEN SC.Sno IS null AND SC.Cno IS null THEN '' ELSE isnull(CAST(SC.Cno as char(10)), '學生') END Cno,
    CASE WHEN SC.Sno IS null AND SC.Cno IS null THEN '' ELSE isnull(CAST(C.Cname as char(10)), '平均分') END Cname,
    AVG(Degree) 成績
FROM Score SC
JOIN Student S ON S.Sno = SC.Sno
JOIN Course C ON C.Cno = SC.Cno
GROUP BY GROUPING SETS ((sc.Cno, sc.Sno, Sname, Cname), (SC.Sno, S.Sname), (SC.Cno, C.Cname))

參考資料

《SqlServer 2014 數據庫技術實用教程》,胡伏湘、肖玉朝 主編,清華大學出版社


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM