你真的會玩SQL嗎?系列目錄
本章的內容與 你真的會玩SQL嗎?透視轉換內容 非常重要,非常重要,非常重要 ,不理解的可以慢慢看,回頭看,過幾天再看,以后很多思想需要以此為基礎而演變。
此后用到的用例數據庫是SQL2008里面的,若看過本系列之前的文章,創建過基礎樣例數據庫就不用再創建。
若沒有創建過的,用例數據庫文件:鏈接:http://pan.baidu.com/s/1qW1QxA0 密碼:dqxx
連續聚合
下面的例子將使用一個EmpOrdersr匯總表,每位雇員在每個月占一行,包含該雇員在一個月內處理過的訂單數量,運行下代碼創建數據:
CREATE TABLE EmpOrders ( empid INT NOT NULL , ordmonth DATE NOT NULL ,--只取到月份2015-07-07 qty INT NOT NULL , PRIMARY KEY ( empid, ordmonth ) ) go INSERT INTO EmpOrders ( empid , ordmonth , qty ) SELECT o.empid , DATEADD(MONTH, DATEDIFF(MONTH, 0, o.orderdate), 0) AS ordmonth , SUM(qty) AS qty FROM Sales.Orders AS o JOIN Sales.OrderDetails AS od ON o.orderid = od.orderid GROUP BY empid , DATEADD(MONTH, DATEDIFF(MONTH, 0, o.orderdate), 0)
查詢:
SELECT empid , ordmonth , qty FROM EmpOrders ORDER BY empid , ordmonth
將輸出以下內容
接下來講講各類聚合……
1.累積聚合
為每個雇員和每個月,返回從其開始有訂單操作以來到該月份處理過的訂單總量和每月的平均量,結果如下,怎么做?
SELECT o1.empid , o1.ordmonth , o1.qty AS qtythismonth , SUM(o2.qty) AS totalqty , CAST(AVG(1. * o2.qty) AS NUMERIC(12, 2)) AS avgqty FROM EmpOrders AS o1 JOIN EmpOrders AS o2 ON o2.empid = o1.empid AND o2.ordmonth <= o1.ordmonth GROUP BY o1.empid , o1.ordmonth , o1.qty ORDER BY o1.empid , o1.ordmonth
若想得到雇員達到累積總量<1000之前的每月聚合值,怎么做?
SELECT o1.empid , o1.ordmonth , o1.qty AS qtythismonth , SUM(o2.qty) AS totalqty , CAST(AVG(1. * o2.qty) AS NUMERIC(12, 2)) AS avgqty FROM EmpOrders AS o1 JOIN EmpOrders AS o2 ON o2.empid = o1.empid AND o2.ordmonth <= o1.ordmonth GROUP BY o1.empid , o1.ordmonth , o1.qty HAVING SUM(o2.qty)<1000 ORDER BY o1.empid , o1.ordmonth
對總量做一次HAVING過濾 HAVING SUM(o2.qty)<1000,而不是用WHERE,因為過濾是的聚合,而不是屬性。
2.滑動聚合
滑動聚合是對序列內的一個滑動窗口進行的聚合計算,而不是從序列的開始計算到當前位置。
求雇員最近三個月(包括本月)的平均訂單量(移動平均數),得到以下結果:

SELECT o1.empid , o1.ordmonth , o1.qty AS qtythismonth , SUM(o2.qty) AS totalqty , CAST(AVG(1. * o2.qty) AS NUMERIC(12, 2)) AS avgqty FROM EmpOrders AS o1 JOIN EmpOrders AS o2 ON o2.empid = o1.empid AND (o2.ordmonth <= o1.ordmonth AND o2.ordmonth > DATEADD(MONTH,-3,o1.ordmonth)) GROUP BY o1.empid , o1.ordmonth , o1.qty ORDER BY o1.empid , o1.ordmonth
這里使用的是o2.ordmonth> 3個月之前的月份 and o2.ordmonth<=o1.當前月份
3.年初至今
聚合按年單位算,如求每個雇員每年內的每個月份的聚合,該怎樣寫?結果如下:

SELECT o1.empid , CONVERT( VARCHAR(7),o1.ordmonth ,121) AS ordmonth, o1.qty AS qtythismonth , SUM(o2.qty) AS totalqty , CAST(AVG(1. * o2.qty) AS NUMERIC(12, 2)) AS avgqty FROM EmpOrders AS o1 JOIN EmpOrders AS o2 ON o2.empid = o1.empid AND ( o2.ordmonth <= o1.ordmonth AND o2.ordmonth >= CAST(CAST(YEAR(o1.ordmonth) AS CHAR(4)) + '0101' AS DATETIME) ) GROUP BY o1.empid , o1.ordmonth , o1.qty ORDER BY o1.empid , o1.ordmonth
所有聚合函數都會忽略NULL值,只有一個例外:Count(*)
聚合中常見的函數為分組函數GROUP BY ,要注意的是 GROUP BY 原則 select后面所有列中 沒有使用聚合函數的列必須出現在GROUP BY 后面