1. 程式人生 > >T-SQL查詢: PIVOT/UNPIVOT 邏輯操作步驟

T-SQL查詢: PIVOT/UNPIVOT 邏輯操作步驟

--【PIVOT】


USE tempdb
GO

--	DROP TABLE #test
CREATE TABLE #test(Empid int,Oderyear varchar(4),val numeric(18,2))

INSERT INTO #test(Empid,Oderyear,val)
VALUES
	(1,'2012',156823),
	(1,'2013',256833.56),
	(1,'2014',456823.33),
	(3,'2014',26536.69),
	(4,'2012',56823.85),
	(4,'2013',452365.23),
	(2,'2014',56213),
	(3,'2013',456123),
	(4,'2014',256423.33)
	


SET STATISTICS PROFILE ON --檢視執行計劃

SELECT * FROM  #test
PIVOT(
	MAX(VAL) FOR Oderyear IN([2012],[2013],[2014])
) AS T

/*
SELECT * FROM  #test  PIVOT(   MAX(VAL) FOR Oderyear IN([2012],[2013],[2014])  ) AS T
     |--Stream Aggregate(GROUP BY:([tempdb].[dbo].[#test].[Empid]) DEFINE:(
		[Expr1004]=MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2012' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END)
		[Expr1005]=MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2013' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END)
		[Expr1006]=MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2014' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END))
       |--Sort(ORDER BY:([tempdb].[dbo].[#test].[Empid] ASC))
            |--Table Scan(OBJECT:([tempdb].[dbo].[#test]))

1. 讀取表[#test]
2. 表排序[#test].[Empid] ASC
3. 聚合查詢(按查詢的步驟執行)
	3.1 分組GROUP BY:([tempdb].[dbo].[#test].[Empid])
	3.2 擴充套件,將IN子句擴充套件到相應目標列
		,CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2012' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END
		,CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2013' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END
		,CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2014' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END
	3.3 聚合
		,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2012' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2012]
		,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2013' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2013]
		,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2014' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2014]
*/
  
--邏輯上等效如下:
SELECT [tempdb].[dbo].[#test].[Empid]
,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2012' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2012]
,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2013' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2013]
,MAX(CASE WHEN [tempdb].[dbo].[#test].[Oderyear]='2014' THEN [tempdb].[dbo].[#test].[val] ELSE NULL END) AS [2014]
FROM [tempdb].[dbo].[#test]
GROUP BY [tempdb].[dbo].[#test].[Empid]

/*結果:
Empid	2012	2013		2014
-----	-----	--------	--------
1	156823.00	256833.56	456823.33
2	NULL		NULL		56213.00
3	NULL		456123.00	26536.69
4	56823.85	452365.23	256423.33

*/




--【UNPIVOT】
--	DROP TABLE #test2

SELECT * INTO #test2 FROM  #test
PIVOT(
	MAX(VAL) FOR Oderyear IN([2012],[2013],[2014])
) AS T

--以剛才的結果為例

SELECT Empid,Oderyear,val FROM  #test2
UNPIVOT(
	VAL FOR Oderyear IN([2012],[2013],[2014])
) AS T

/*執行計劃:
SELECT Empid,Oderyear,val FROM  #test2  UNPIVOT(   VAL FOR Oderyear IN([2012],[2013],[2014])  ) AS T
  |--Filter(WHERE:([Expr1008] IS NOT NULL))
       |--Nested Loops(Left Outer Join, OUTER REFERENCES:(
		[tempdb].[dbo].[#test2].[2012],[tempdb].[dbo].[#test2].[2013],[tempdb].[dbo].[#test2].[2014]))
            |--Compute Scalar(DEFINE:([Expr1004]=[tempdb].[dbo].[#test2].[Empid]))
            |    |--Table Scan(OBJECT:([tempdb].[dbo].[#test2]))
            |--Constant Scan(VALUES:(
            (N'2012',[tempdb].[dbo].[#test2].[2012]),(N'2013',[tempdb].[dbo].[#test2].[2013]),(N'2014',[tempdb].[dbo].[#test2].[2014])))
1. 讀取表[#test2]
2. 巢狀連線[Empid]與
			(N'2012',[tempdb].[dbo].[#test2].[2012]),
			(N'2013',[tempdb].[dbo].[#test2].[2013]),
			(N'2014',[tempdb].[dbo].[#test2].[2014])
	生成3個副本,IN子句有幾個列就生成幾個副本
	結果:
	Empid	2012	2013		2014		Oderyear
	-----	-----	--------	--------	----
	1	156823.00	256833.56	456823.33	2012
	1	156823.00	256833.56	456823.33	2013
	1	156823.00	256833.56	456823.33	2014
	2	NULL		NULL		56213.00	2012
	2	NULL		NULL		56213.00	2013
	2	NULL		NULL		56213.00	2014
	3	NULL		456123.00	26536.69	2012
	3	NULL		456123.00	26536.69	2013
	3	NULL		456123.00	26536.69	2014
	4	56823.85	452365.23	256423.33	2012
	4	56823.85	452365.23	256423.33	2013
	4	56823.85	452365.23	256423.33	2014

3. 提取元素,VAL FOR Oderyear 中保留對應的值
	結果:
	Empid	VAL		Oderyear
	-----	-----	--------
	1	156823.00	2012
	1	256833.56	2013
	1	456823.33	2014
	2	NULL		2012
	2	NULL		2013
	2	56213.00	2014
	3	NULL		2012
	3	456123.00	2013
	3	26536.69	2014
	4	56823.85	2012
	4	452365.23	2013
	4	256423.33	2014

4. 過濾空值行Filter(WHERE:([Expr1008] IS NOT NULL)
	結果:
	Empid	VAL		Oderyear
	-----	-----	--------
	1	156823.00	2012
	1	256833.56	2013
	1	456823.33	2014
	2	56213.00	2014
	3	456123.00	2013
	3	26536.69	2014
	4	56823.85	2012
	4	452365.23	2013
	4	256423.33	2014

*/