[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

输出结果:

image


来看下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


输出结果

image

 

可以看出来,转换完成了,就这么个功能

再看一个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

image

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

 

猜测您可能对下边的文章感兴趣

SQL SERVER 2008 函数大全 - 字符串函数

SQL2008系统统计函数

[MSSQL]GROUPING SETS,ROLLUP,CUBE初体验

[MSSQL]ROW_NUMBER函数

[MSQL]RANK函数

[MSSQL]NTILE另类分页有么有?!

[MSQL]也说SQL中显示星期几函数

[MSSQL]COALESCE与ISNULL函数

[MSSQL]PIVOT函数

[MSSQL]FOR XML AUTO I

[MSSQL]FOR XML AUTO II

[MSSQL]TRY…CATCH…通用格式

如果您喜欢该博客请点击右下角推荐按钮,您的推荐是作者创作的动力!

posted @ 2011-08-19 14:32  kkun  阅读(7709)  评论(1编辑  收藏  举报