SQL Server:带有标题的动态数据透视表,包括列名和日期

时间:2013-04-10 23:08:50

标签: sql sql-server tsql pivot unpivot

我正在尝试使用动态数据透视,并需要将行转换为列的帮助

表格如下:

ID   expense  revenue date
1    43       45      12-31-2012   
1    32       32      01-01-2013 
3    64       56      01-31-2013
4    31       32      02-31-2013

我需要报告目的,如

ID  expense12-31-2012  expense01-01-2013 expense01-31-2013 revenue12-31-2013
1   43                 32                
3                                        64

1 个答案:

答案 0 :(得分:2)

为了将expenserevenue列作为date的标题,我建议同时应用UNPIVOT和PIVOT函数。

UNPIVOT会将费用和收入列转换为您可以追加日期的行。将日期添加到列名称后,即可应用PIVOT功能。

UNPIVOT代码将是:

select id, 
  col+'_'+convert(varchar(10), date, 110) new_col, 
  value
from yt
unpivot
(
  value
  for col in (expense, revenue)
) un

SQL Fiddle with Demo。这会产生一个结果:

| ID |            NEW_COL | VALUE |
-----------------------------------
|  1 | expense_12-31-2012 |    43 |
|  1 | revenue_12-31-2012 |    45 |
|  2 | expense_01-01-2013 |    32 |

正如您所看到的,费用/收入列现在是通过将日期连接到结尾而创建的new_col行。然后在PIVOT中使用此new_col

select id,
  [expense_12-31-2012], [revenue_12-31-2012],
  [expense_01-01-2013], [revenue_01-01-2013],
  [expense_01-31-2013], [revenue_01-31-2013],
  [expense_03-03-2013], [revenue_03-03-2013]
from
(
  select id, 
    col+'_'+convert(varchar(10), date, 110) new_col, 
    value
  from yt
  unpivot
  (
    value
    for col in (expense, revenue)
  ) un
) src
pivot
(
  sum(value)
  for new_col in ([expense_12-31-2012], [revenue_12-31-2012],
                  [expense_01-01-2013], [revenue_01-01-2013],
                  [expense_01-31-2013], [revenue_01-31-2013],
                  [expense_03-03-2013], [revenue_03-03-2013])
) piv;

请参阅SQL Fiddle with Demo

如果你有一个已知数量的日期变成列,但如果你有一个未知数量的日期,那么上面的版本将会很好用,那么你将需要使用动态SQL来生成结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(c.col+'_'+convert(varchar(10), yt.date, 110)) 
                    from yt
                    cross apply
                    (
                      select 'expense' col union all
                      select 'revenue'
                    ) c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id,' + @cols + ' 
            from
            (
              select id, 
                col+''_''+convert(varchar(10), date, 110) new_col, 
                value
              from yt
              unpivot
              (
                value
                for col in (expense, revenue)
              ) un
            ) src
            pivot 
            (
                sum(value)
                for new_col in (' + @cols + ')
            ) p '

execute(@query);

SQL Fiddle with Demo。两个查询都会生成相同的结果。