介紹一種非常好用匯總數據的方式GROUPING SETS
介紹
對於任何人而言,用T-SQL語句來寫聚會查詢都是工作中重要的一環。我們大家也都很熟悉GROUP BY子句來實現聚合表達式,但是如果打算在一個結果集中包含多種不同的匯總結果,可能會比較麻煩。我將舉例展示給大家使用GROUPING SETS操作符來完成這個“混合的結果集”。
或許當我們在打算分析較大規模的數據集時,不知道從何下手,此時處理這種情況最好的方式就是匯總數據,快速的得到一個數據預覽。
在T-SQL中,使用GROUP BY子句在一個聚合查詢中來匯總需要的數據。這個子句由一組表達式定義的分組構成。結果集中每一行返回GROUP BY 子句中表達式的唯一值或者組合,並且聚合函數,像COUNT或者SUM等可以對查詢中的任何行進行聚合。但是,如果你想要多種不同組合的聚合時,一般有兩種方式:
1.將不懂組合聚合的結果集UNIONALL在一起。
2.使用 GROUPING SETS操作符,結合GROUP BY一起在一個語句中實現。
本文中,我會展示如何使用GROUPING SETS來實現這一目的。
準備數據集
本文中所有的查詢都使用AdventureWorks2012 數據庫中的數據,這裏提供一個下載地址方便使用(AdventureWorks2012)
實例: Data Analyst at Adventure Works
比如你是一個數據分析師,對於公司今年的收入很感興趣。這意味著你需要分組匯總公司的每一年的收入,查詢語句如下:
Query 1. 匯總每年收入
USE AdventureWorks2012;
GO
SELECT
YEAR(OrderDate) AS OrderYear,
SUM(SubTotal) AS Income
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate)
ORDER BY OrderYear;
GO
Query 1 返回結果集:
OrderYear |
Income |
2005 |
11331809 |
2006 |
30674773.2 |
2007 |
42011037.2 |
2008 |
25828762.1 |
根據這個結果集,可知該公2005到2008年的收入情況。這類數據信息對於商業分析來說很常見。
但是,如果你想要更多關於收入的信息,比如其他匯總條件,你必須要重新運行一個GROUP BY子句。比如查詢返回公司每個月的收入情況。查詢語句如下:
Query 2. 公司每個月的收入
SELECT
YEAR(OrderDate) AS OrderYear,
MONTH(OrderDate) AS OrderMonth,
SUM(SubTotal) AS Income
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate), MONTH(OrderDate)
ORDER BY OrderYear, OrderMonth;
GO
結果集如下:
OrderYear |
OrderMonth |
Income |
2005 |
7 |
962716.742 |
2005 |
8 |
2044600 |
2005 |
9 |
1639840.11 |
2005 |
10 |
1358050.47 |
2005 |
11 |
2868129.2 |
2005 |
12 |
2458472.43 |
2006 |
1 |
1309863.25 |
2006 |
2 |
2451605.62 |
2006 |
3 |
2099415.62 |
2006 |
4 |
1546592.23 |
2006 |
5 |
2942672.91 |
2006 |
6 |
1678567.42 |
2006 |
7 |
2894054.68 |
2006 |
8 |
4147192.18 |
2006 |
9 |
3235826.19 |
2006 |
10 |
2217544.45 |
2006 |
11 |
3388911.41 |
2006 |
12 |
2762527.22 |
2007 |
1 |
1756407.01 |
2007 |
2 |
2873936.93 |
2007 |
3 |
2049529.87 |
2007 |
4 |
2371677.7 |
2007 |
5 |
3443525.25 |
2007 |
6 |
2542671.93 |
2007 |
7 |
3554092.32 |
2007 |
8 |
5068341.51 |
2007 |
9 |
5059473.22 |
2007 |
10 |
3364506.26 |
2007 |
11 |
4683867.05 |
2007 |
12 |
5243008.13 |
2008 |
1 |
3009197.42 |
2008 |
2 |
4167855.43 |
2008 |
3 |
4221323.43 |
2008 |
4 |
3820583.49 |
2008 |
5 |
5194121.52 |
2008 |
6 |
5364840.18 |
2008 |
7 |
50840.63 |
這個結果集要比之前的更詳細一點。可以得到具體某個月的收入匯總。顯然GROUP BY 後面的列越多其越詳細,結果一般也越多(除非有傳遞依賴鍵)。
如果你仔細觀察兩個查詢,你會發現他們都是根據個子的分組表達式進行分組匯總的。前面的是按照年,後面的是按照年和月。
假如我想查看兩種匯總結果在一個結果集中應該怎麽處理那?為了實現這個目標,我們前面說了兩個方案,方案1就是使用UNION ALL,代碼如下:
Query 3. 公司收入(每年|每月)
SELECT
YEAR(OrderDate) AS OrderYear,
NULL AS OrderMonth, --Dummy Column
SUM(SubTotal) AS Incomes
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate)
UNION ALL
SELECT
YEAR(OrderDate) AS OrderYear,
MONTH(OrderDate) AS OrderMonth,
SUM(SubTotal) AS Incomes
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate), MONTH(OrderDate)
ORDER BY OrderYear, OrderMonth;
GO
結果集如下圖所示:
其中紅色框內為按照年的匯總數據。藍色框內為按照年和月的分組匯總。
如圖所示兩個結果集被合並在一起了。註意。此時NULL出現在裏面,使用NULL作為假列來標識order year分組的結果。因為按年分組沒有這個列。
盡管你已經獲得了想要的結果,但是這樣需要完成兩次的語句,接下來我們嘗試一下grouping set,方案2。因為我們都是懶人嗎,所以這個方式一定要更加簡單。目的就是“更少代碼,相同結果”。接下來我們詳細看一下:
Query 4.使用 GROUPING SETS實現相同結果
SELECT
YEAR(OrderDate) AS OrderYear,
MONTH(OrderDate) AS OrderMonth,
SUM(SubTotal) AS Incomes
FROM Sales.SalesOrderHeader
GROUP BY
GROUPING SETS
(
YEAR(OrderDate), --1st grouping set
(YEAR(OrderDate),MONTH(OrderDate)) --2nd grouping set
);
GO
結果集跟之前的一模一樣。但是新的代碼要少很多。GROUPING SETS 操作符要和GROUP BY 子句在一起使用。並且允許我們可以做一個多分組的查詢。盡管如此,我們要仔細檢查指定的分組集。例如假如一個分組包含兩個列,假設列A和B,兩個列都需要包含在括號內:(column A, column B)。如果沒有括號,這個子句將會被定義為獨立的分組,結果就不同了。
上面語句的結果如下:
順便說一下,如果我們打算聚合整個結果集(不分組聚合所有數據),只需要添加有一個空的括號在分組集裏面即可。查詢語句如下:
Query 5. 加入總體匯總結果
SELECT
YEAR(OrderDate) AS OrderYear,
MONTH(OrderDate) AS OrderMonth,
SUM(SubTotal) AS Incomes
FROM Sales.SalesOrderHeader
GROUP BY
GROUPING SETS
(
YEAR(OrderDate), --1st grouping set
(YEAR(OrderDate),MONTH(OrderDate)), --2nd grouping set
() --3rd grouping set (grand total)
);
GO
結果如圖:
註意最下方的42行,年月都為null,這個查詢匯總了鄭鐵的所有收入,因為沒有進行任何分組。
註意,需要強調一個十強,一定要確保分組列字段部位NULL,因此NULLS不能被用作分組列在GROUPING SETS中使用。如果非要那個為空字段,需要使用 GROUPING 或者 GROUPING_ID 函數判斷是否NULL來自GROUPING SETS 操作符。
總結
本篇文章中,主要介紹如何使用另一種聚合查詢方式來實現多種分組聚合結果的合並。熟悉後你會發現這種方式對於總結匯總數據非常有幫助,大大提高了我們代碼的效率。
介紹一種非常好用匯總數據的方式GROUPING SETS