T-sql枢轴功能

时间:2012-09-15 06:46:36

标签: sql sql-server tsql pivot unpivot

我需要转换下表

quarter   cal_year  blue    green   yellow  red

DEC 2011        +31%    25-30%  22-24%  -21%

MAR 2012        +61%    50-60%  43-49%  -42%
进入这个。有没有一种简单的方法来实现它?

Color   DEC     MAR     
blue    +31%    +61%    
green   25-30%  50-60%  
yellow  22-24%  43-49%  
red     -21%    -42%    

2 个答案:

答案 0 :(得分:3)

虽然@ Joro的版本可以使用,但我会这样做略有不同,因为在这种情况下不需要CTE。

您知道要转换的列的PIVOT的静态版本:

select col, [Mar], [Dec]
from 
(
  select quarter, val, col
  from yourtable
  unpivot
  (
    val
    for col in (blue, green, yellow, red)
  )u
) x
pivot
(
  max(val)
  for quarter in ([Mar], [Dec])
) p

请参阅SQL Fiddle with Demo

动态版本,其中列是在运行时确定的:

DECLARE @colsPivot AS NVARCHAR(MAX),
    @colsUnpivot as NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsPivot = STUFF((SELECT distinct ',' + QUOTENAME(Quarter) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name not in ('Quarter', 'cal_year')
         for xml path('')), 1, 1, '')

set @query 
  = 'select *
      from
      (
        select quarter, val, col
        from yourtable
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for quarter in ('+ @colspivot +')
      ) p'

exec(@query)

请参阅SQL Fiddle with Demo

如果您只有几列,那么您也可以使用CASE语句和UNION ALL

执行此操作
select col,
  max(case when quarter = 'MAR' then val end) MAR,
  max(case when quarter = 'DEC' then val end) DEC
from
(
  select quarter, val, col
  from
  (
    select quarter, blue as val, 'blue' as col
    from yourtable
    union all
    select quarter, green as val, 'green' as col
    from yourtable
    union all
    select quarter, yellow as val, 'yellow' as col
    from yourtable
    union all
    select quarter, red as val, 'red' as col
    from yourtable
  ) u
) x
group by col

请参阅SQL Fiddle with Demo

答案 1 :(得分:1)

以下是一种方法:

DECLARE @SourceTable TABLE
(
    [Quarter] NVARCHAR(20),
    [cal_year] BIGINT,
    [blue] NVARCHAR(20),
    [green] NVARCHAR(20),
    [yellow] NVARCHAR(20),
    [red] NVARCHAR(20)
)

INSERT INTO @SourceTable ([Quarter],[cal_year],[blue],[green],[yellow],[red])
VALUES  ('DEC',2011,'+31%','25-30%','22-24%','-21%')
       ,('MAR',2012,'+61%','50-60%','43-49%','-42%')


;WITH CTE([Quarter],[Color],[Value]) AS
(
    SELECT [Quarter],[Color],[Value]
    FROM
        (
            SELECT [Quarter],[blue],[green],[yellow],[red]
            FROM @SourceTable
        ) data
    UNPIVOT
    (
         [Value] FOR [Color] IN ([blue],[green],[yellow],[red])
    )AS unpvt
)
SELECT *
FROM 
(
    SELECT Color,[Quarter],Value
    FROM CTE
)AS src
PIVOT
(
    MAX(Value) FOR [Quarter] IN ([MAR],[DEC] )

) AS pvtTbl

但我们假设您有更多数据要比较:

CREATE TABLE #SourceTable
(
    [Quarter] NVARCHAR(20),
    [cal_year] BIGINT,
    [blue] NVARCHAR(20),
    [green] NVARCHAR(20),
    [yellow] NVARCHAR(20),
    [red] NVARCHAR(20)
)

INSERT INTO #SourceTable ([Quarter],[cal_year],[blue],[green],[yellow],[red])
VALUES   ('DEC',2011,'+31%','25-30%','22-24%','-21%')
        ,('JAN',2012,'+11%','10-20%','13-49%','-12%')
        ,('FEB',2012,'+31%','25-35%','12-14%','-11%')
        ,('MAR',2012,'+71%','10-45%','13-59%','-11%')
        ,('APR',2012,'+11%','15-15%','12-24%','-51%')
        ,('MAY',2012,'+11%','40-60%','13-39%','-43%')


DECLARE @DynamicSQLStatement NVARCHAR(MAX)

SET @DynamicSQLStatement=N';WITH CTE([Quarter],[Color],[Value]) AS
                         (
                             SELECT [Quarter],[Color],[Value]
                             FROM
                                 (
                                     SELECT [Quarter],[blue],[green],[yellow],[red]
                                     FROM #SourceTable
                                 ) data
                             UNPIVOT
                             (
                                    [Value] FOR [Color] IN ([blue],[green],[yellow],[red])
                             )AS unpvt
                         )
                         SELECT *
                         FROM 
                         (
                             SELECT Color,[Quarter],Value
                             FROM CTE
                         )AS src
                         PIVOT
                         (
                             MAX(Value) FOR [Quarter] IN ('+(SELECT SUBSTRING((SELECT '],[' + [Quarter] FROM #SourceTable FOR XML PATH('')),3,200)+']')+')
                         ) AS pvtTbl'

EXECUTE sp_executesql @DynamicSQLStatement


DROP TABLE #SourceTable

注意,如果您希望在不同年份的相同月份工作,则应优化最后一个示例。