[MSSQL]PIVOT函数
PIVOT在帮助中这样描述滴:
可以使用 PIVOT 和 UNPIVOT 关系运算符将表值表达式更改为另一个表。PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合。UNPIVOT 与 PIVOT 执行相反的操作,将表值表达式的列转换为列值。
简单点理解就是行变列,UNPIVOT则是列变行,一个一个看
测试用的数据及表结构:
CREATE TABLE ShoppingCart(
[Week] INT NOT NULL,
[TotalPrice] DECIMAL DEFAULT(0) NOT NULL
)
INSERT INTO ShoppingCart([Week],[TotalPrice])
SELECT 1,10 UNION ALL
SELECT 2,20 UNION ALL
SELECT 3,30 UNION ALL
SELECT 4,40 UNION ALL
SELECT 5,50 UNION ALL
SELECT 6,60 UNION ALL
SELECT 7,70
SELECT * FROM ShoppingCart
输出结果:
来看下PIVOT怎么把行变列:
SELECT 'TotalPrice' AS [Week],[1],[2],[3],[4],[5],[6],[7]
FROM ShoppingCart PIVOT(SUM(TotalPrice) FOR [Week] IN([1],[2],[3],[4],[5],[6],[7])) AS T
输出结果
可以看出来,转换完成了,就这么个功能
再看一个UNPIVOT函数,与上述功能相反,把列转成行
我们直接使用WITH关键字把上述PIVOT查询当成源表,然后再使用UNPIVOT关键把它旋转回原来的模样,SQL脚本及结果如下:
WITH P AS (
SELECT 'TotalPrice' AS [Week],[1],[2],[3],[4],[5],[6],[7]
FROM ShoppingCart PIVOT(SUM(TotalPrice) FOR [Week] IN([1],[2],[3],[4],[5],[6],[7]))
AS T
)
SELECT
[WeekDay] AS [Week],
[WeekPrice] AS [TotalPrice]
FROM P
UNPIVOT(
[WeekPrice] FOR [WeekDay] IN([1],[2],[3],[4],[5],[6],[7])
)AS FOO
OK介绍完了,大概功能如此,但使用起来远不止如此,灵活运用威力无穷~
下边这个SQL语句,下边大段注释部分为前同事的作品,上半部分是我重写后的,可以看到,代码量减少了不少!多提宝贵意见!
1: ALTER PROCEDURE [dbo].[Report_ApplyStat]
2: @TenantId int
3: AS
4: BEGIN
5: /* 模板表 */
6: DECLARE @TEMP TABLE([aType] INT)
7: INSERT INTO @TEMP([aType])VALUES(1),(2);
8:
9: /* 查询条件 */
10: WITH CONDITION AS(
11: SELECT
12: SC.PersonId,
13: ISNULL(RE.PhaseId,0) AS [PhaseId],
14: DATEDIFF(MONTH,SC.ApplyDate,GETDATE()) AS DIFF
15: FROM SearchCV SC
16: LEFT JOIN [REL_PersonJobStoreDB] RE ON SC.PersonId = RE.PersonId
17: WHERE SC.TenantId = @TenantId),
18: [ApplyCount] AS(SELECT 1 AS [TYPE],DATEDIFF(MONTH,ApplyDate,GETDATE()) AS DIFF,(PersonId) AS [ApplyCount] FROM SearchCV WHERE TenantId = @TenantId),
19: [OfferCount] AS(SELECT 2 AS [TYPE],DIFF,(PersonId) AS [OfferCount] FROM CONDITION WHERE PhaseId = 4 ),
20: [Result] AS(
21: SELECT [TYPE] AS [aType],[1],[2],[3],[4],[5],[6] FROM [ApplyCount] PIVOT(COUNT([ApplyCount]) FOR DIFF IN([1],[2],[3],[4],[5],[6]))AS T UNION ALL
22: SELECT [TYPE] AS [aType],[1],[2],[3],[4],[5],[6] FROM [OfferCount] PIVOT(COUNT([OfferCount]) FOR DIFF IN([1],[2],[3],[4],[5],[6]))AS T )
23: SELECT
24: TP.[aType] AS [aType],
25: ISNULL(RE.[6],0) AS [M1],
26: ISNULL(RE.[5],0) AS [M2],
27: ISNULL(RE.[4],0) AS [M3],
28: ISNULL(RE.[3],0) AS [M4],
29: ISNULL(RE.[2],0) AS [M5],
30: ISNULL(RE.[1],0) AS [M6]
31: FROM @TEMP TP
32: LEFT JOIN [Result] RE ON TP.[aType] = RE.[aType] Order by TP.aType
33:
34: --定义表变量
35:
36: --declare @TenantId INT
37: --select @TenantId=100001
38: --DECLARE @temp1 table(
39: -- aType INT DEFAULT(0),
40: -- mon int,--取今天与入库时间的月份差,如SELECT DATEDIFF(MONTH,'2010-7-1',GETDATE()) = 2
41: -- total int
42: -- )
43: --DECLARE @temp2 table(
44: -- aType int NOT NULL default 0,
45: -- mon varchar(40),
46: -- total int)
47: --DECLARE @stat_date DATETIME
48: --DEClARE @Index int
49: --declare @s varchar(4000), @sql varchar(4000)
50: --SET @s = ''
51: --SET @Index=1
52: --SET @stat_date = GETDATE()-150
53: ----遍历出要统计的月份
54: --WHILE month(@stat_date) <= month(GETDATE())
55: --BEGIN
56: -- Select @s=@s+ 'M'+convert(varchar(20),@Index)+ ' = max(case when mon = '+QUOTENAME(left(CONVERT(varchar,@stat_date,102),7),'''')+ ' then total else 0 end),'
57: -- SET @stat_date=DATEADD(MONTH, 1, @stat_date)
58: -- SET @Index=@Index+1
59:
60: --END
61: --Select @s= SUBSTRING(@s,0,len(@s))
62: --print @s
63:
64: --应聘总数
65: --insert into @temp1(aType,mon,total)
66: --select 1,DATEDIFF(MONTH,CreateDate,GETDATE()) AS mon,COUNT(*) total from [REL_PersonJobStoreDB] where TenantId=@TenantId group by DATEDIFF(MONTH,CreateDate,GETDATE())
67: --IF(NOT EXISTS(SELECT 1 FROM @temp1))
68: --BEGIN
69: -- insert into @temp1(aType,mon,total)
70: -- SELECT 1,-1,0
71: --END
72: ----匹配应聘标识号
73: --Update @temp1 set aType=1
74:
75: --已录用人数
76: --insert into @temp1(aType,mon,total)
77: --select 2,DATEDIFF(MONTH,CreateDate,GETDATE()),COUNT(*) total from [REL_PersonJobStoreDB] where TenantId=@TenantId and PhaseId = 4 group by DATEDIFF(MONTH,CreateDate,GETDATE())
78: --IF(NOT EXISTS(SELECT 1 FROM @temp1 WHERE aType=2))
79: --BEGIN
80: -- insert into @temp1(aType,mon,total)
81: -- SELECT 2,-1,0
82: --END
83:
84: --SELECT * FROM @temp1
85: --匹配应聘标识号
86: --Update @temp2 set aType=2
87: ----合并表数据
88: --insert into @temp1 select * from @temp2
89:
90: --select * from @temp1
91:
92: --DECLARE @DATE DATETIME
93: --SET @DATE = GETDATE()
94: --SELECT GETDATE(),DATEADD(MONTH,-1,GETDATE()),DATEDIFF(MONTH,GETDATE(),DATEADD(MONTH,1,GETDATE()))
95: --select aType,mon,avg(total) total from @temp1
96: -- group by atype,mon
97:
98: --select [aType],
99: --M1 = max(case when mon = 6 then total else 0 end),
100: --M2 = max(case when mon = 5 then total else 0 end),
101: --M3 = max(case when mon = 4 then total else 0 end),
102: --M4 = max(case when mon = 3 then total else 0 end),
103: --M5 = max(case when mon = 2 then total else 0 end),
104: --M6 = max(case when mon = 1 then total else 0 end)
105: --from
106: --(
107: -- select aType,mon,avg(total) total from @temp1
108: -- group by atype,mon
109: -- ) aa
110: -- group by [aType]
111:
112:
113:
114: -- print @sql
115: --exec(@sql)
116:
117: END
原代码即为32行以后,新代码为前32行,显然重构后减少了Bad Smell
猜测您可能对下边的文章感兴趣
[MSSQL]GROUPING SETS,ROLLUP,CUBE初体验
如果您喜欢该博客请点击右下角推荐按钮,您的推荐是作者创作的动力!
------------------------------------------
除非特别声明,文章均为原创,版权与博客园共有,转载请保留出处
BUY ME COFFEE