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语句,下边大段注释部分为前同事的作品,上半部分是我重写后的,可以看到,代码量减少了不少!多提宝贵意见!
PROCEDURE [dbo].[Report_ApplyStat]
int
AS
BEGIN
/* 模板表 */
INT)
VALUES(1),(2);
8:
/* 查询条件 */
AS(
SELECT
12: SC.PersonId,
AS [PhaseId],
AS DIFF
FROM SearchCV SC
ON SC.PersonId = RE.PersonId
WHERE SC.TenantId = @TenantId),
WHERE TenantId = @TenantId),
WHERE PhaseId = 4 ),
AS(
ALL
AS T )
SELECT
AS [aType],
AS [M1],
AS [M2],
AS [M3],
AS [M4],
AS [M5],
AS [M6]
FROM @TEMP TP
by TP.aType
33:
34: --定义表变量
35:
INT
select @TenantId=100001
table(
-- aType INT DEFAULT(0),
-- mon int,--取今天与入库时间的月份差,如SELECT DATEDIFF(MONTH,'2010-7-1',GETDATE()) = 2
-- total int
-- )
table(
-- aType int NOT NULL default 0,
-- mon varchar(40),
-- total int)
DECLARE @stat_date DATETIME
int
varchar(4000)
''
Index=1
SET @stat_date = GETDATE()-150
53: ----遍历出要统计的月份
month(GETDATE())
BEGIN
-- 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),'
-- SET @stat_date=DATEADD(MONTH, 1, @stat_date)
-- SET @Index=@Index+1
59:
END
SUBSTRING(@s,0,len(@s))
print @s
63:
64: --应聘总数
into @temp1(aType,mon,total)
MONTH,CreateDate,GETDATE())
FROM @temp1))
BEGIN
-- insert into @temp1(aType,mon,total)
-- SELECT 1,-1,0
END
72: ----匹配应聘标识号
set aType=1
74:
75: --已录用人数
into @temp1(aType,mon,total)
MONTH,CreateDate,GETDATE())
WHERE aType=2))
BEGIN
-- insert into @temp1(aType,mon,total)
-- SELECT 2,-1,0
END
83:
FROM @temp1
85: --匹配应聘标识号
set aType=2
87: ----合并表数据
from @temp2
89:
from @temp1
91:
DATE DATETIME
DATE = GETDATE()
MONTH,1,GETDATE()))
from @temp1
-- group by atype,mon
97:
select [aType],
end),
end),
end),
end),
end),
end)
from
106: --(
-- select aType,mon,avg(total) total from @temp1
-- group by atype,mon
-- ) aa
-- group by [aType]
111:
112:
113:
-- print @sql
sql)
116:
117: END
原代码即为32行以后,新代码为前32行,显然重构后减少了Bad Smell
猜测您可能对下边的文章感兴趣
[MSSQL]GROUPING SETS,ROLLUP,CUBE初体验
如果您喜欢该博客请点击右下角推荐按钮,您的推荐是作者创作的动力!