简体   繁体   中英

T-sql pivot function

I need to convert the following table

quarter   cal_year  blue    green   yellow  red

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

MAR 2012        +61%    50-60%  43-49%  -42%

into this. Is there a simple way to achieve it?

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

While @Joro's version will work, I would do this slightly different since CTE is not needed in this case.

Static Version of the PIVOT where you know the columns to transform:

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

see SQL Fiddle with Demo

Dynamic Version where the columns are determined at run-time:

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)

see SQL Fiddle with Demo

If you only have a few columns, then you can also do this with a CASE statement and a 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

see SQL Fiddle with Demo

Here is one way to do this:

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

But let's suppose that you have more data to compare:

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

Note, you should optimize the last example if you like it to work with same months from different years.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM