SQL Server PIVOT自動化
做此之前,一定要先看過下面2篇
之前做過的樞紐
資料轉向成列表
現在我們要結合這2個,讓樞紐能更自動化
樞紐對人類而言,在資料清單上能一目了然目前的狀況
不過對電腦而言,資料是一筆筆羅列下來,所以在製作樞紐時
我們都必需給他欄位名及對應的資料:
看出端倪了嗎?2002~2004年是手打進去的
這是只有3年,如果要每個月呢? 或是每天?
啊不就打得很痛苦?
所以我們就要結合一個功能叫使用者定義資料類型:
簡單的來講就是讓使用者可以自訂像是 INT NVARCHAR 的類型
流程大致如下:
如此就完成了!!
還有別的做法及引伸題,下面是不用字串,用暫存表
第一題結果:
第二題結果:
之前做過的樞紐
資料轉向成列表
現在我們要結合這2個,讓樞紐能更自動化
樞紐對人類而言,在資料清單上能一目了然目前的狀況
不過對電腦而言,資料是一筆筆羅列下來,所以在製作樞紐時
我們都必需給他欄位名及對應的資料:
看出端倪了嗎?2002~2004年是手打進去的
這是只有3年,如果要每個月呢? 或是每天?
啊不就打得很痛苦?
所以我們就要結合一個功能叫使用者定義資料類型:
簡單的來講就是讓使用者可以自訂像是 INT NVARCHAR 的類型
流程大致如下:
- 定義一個TABLE的類型,並宣告該類型的變數
- 利用之前的方法把資料「橫」起來 → 資料轉向成列表
- 再把所有PIVOT指令串成字串 → 樞紐
- 利用EXECUTE可以執行「字串」的特性來執行 (或是包成PROCEDURE)
第一步:
--先宣告自訂「使用者定差資料表類型」
CREATE TYPE ColumnDataList AS TABLE
(
data NVARCHAR(20)
)
--如此,就可以將變數宣告成我們自訂的ColumnDataList
DECLARE @TT ColumnDataList
INSERT INTO @TT VALUES('aa'),('bb'),('cc')
SELECT * FROM @TT
第二步:
--建立一個函數將資料橫起來,注意自訂類型一定要READONLY CREATE FUNCTION 欄位列表(@Table ColumnDataList READONLY) RETURNS NVARCHAR(MAX) AS BEGIN DECLARE @ColumnName NVARCHAR(MAX) SET @ColumnName = '' SELECT @ColumnName = @ColumnName + '['+ data +'],' FROM @Table IF LEN(@ColumnName) >0 SET @ColumnName = SUBSTRING(@ColumnName,1,LEN(@ColumnName)-1) RETURN @ColumnName END --完成後試看看,看資料有沒有橫放入資料列中 DECLARE @Table ColumnDataList INSERT INTO @Table SELECT DISTINCT 職稱 FROM 員工 SELECT dbo.欄位列表(@Table) DECLARE @Table ColumnDataList INSERT INTO @Table SELECT DISTINCT 職稱 FROM 員工 SELECT dbo.欄位列表(@Table)
第三、四步:
DECLARE @TT ColumnDataList --宣告@TT為自訂的變數
DECLARE @sql NVARCHAR(MAX) --宣告執行的字串
--將每一年獨立放入變數@TT
INSERT INTO @TT SELECT DISTINCT YEAR(訂單日期) AS 訂單年 FROM 訂貨主檔 ORDER BY YEAR(訂單日期)
SET @sql ='
WITH TEMP
AS
(
SELECT YEAR(A.訂單日期) AS 訂單年,D.類別名稱,SUM(B.數量) AS 銷售量
FROM 訂貨主檔 AS A
JOIN 訂貨明細 AS B ON A.訂單號碼 = B.訂單號碼
JOIN 產品資料 AS C ON B.產品編號 = C.產品編號
JOIN 產品類別 AS D ON C.類別編號 = D.類別編號
GROUP BY YEAR(A.訂單日期),D.類別名稱
)
SELECT 類別名稱,' + (SELECT dbo.欄位列表(@TT)) +
' FROM TEMP PIVOT( SUM(銷售量) FOR 訂單年 IN(' + (SELECT dbo.欄位列表(@TT)) +')) AS PP'
--將指令印出來,應該會跟樞紐的指令一模一樣
PRINT(@sql)
--如果一模一樣,就進第四步執行
EXECUTE(@sql)
如此就完成了!!
還有別的做法及引伸題,下面是不用字串,用暫存表
SELECT YEAR(A.訂單日期) AS 訂單年,D.類別名稱,SUM(B.數量) AS 銷售量
INTO #Temp
FROM 訂貨主檔 AS A JOIN 訂貨明細 AS B ON A.訂單號碼=B.訂單號碼
JOIN 產品資料 AS C ON B.產品編號=C.產品編號
JOIN 產品類別 AS D ON C.類別編號=D.類別編號
GROUP BY YEAR(A.訂單日期),D.類別名稱
DECLARE @sql NVARCHAR(MAX)
DECLARE @tt ColumnDataList
INSERT INTO @tt SELECT DISTINCT YEAR(訂單日期) AS 訂單年 FROM 訂貨主檔
SET @sql='SELECT 類別名稱,'+(SELECT dbo.欄位列表(@tt))
SET @sql=@sql+' FROM #Temp PIVOT(SUM(銷售量) FOR 訂單年 IN('+(SELECT dbo.欄位列表(@tt))+')) AS PP'
EXECUTE (@sql)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
--引伸題是做出供應商跟類別名稱的樞紐
SELECT B.供應商,C.類別名稱,COUNT(*) AS 產品數量
INTO #Temp
FROM 產品資料 AS A JOIN 供應商 AS B ON A.供應商編號=B.供應商編號
JOIN 產品類別 AS C ON C.類別編號=A.類別編號
GROUP BY B.供應商,C.類別名稱
DECLARE @sql NVARCHAR(MAX)
DECLARE @tt ColumnDataList
INSERT INTO @tt SELECT DISTINCT 類別名稱 FROM 產品類別
SET @sql='SELECT 供應商,'+(SELECT dbo.欄位列表(@tt))
SET @sql=@sql+' FROM #Temp PIVOT(SUM(產品數量) FOR 類別名稱 IN('+(SELECT dbo.欄位列表(@tt))+')) AS PP'
EXECUTE (@sql)
第一題結果:
第二題結果:





留言
張貼留言