【问题标题】:SQL Server: Dynamic pivot with headers to include column name and dateSQL Server:带有标题的动态数据透视表以包括列名和日期
【发布时间】:2013-04-10 23:08:50
【问题描述】:

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

表格如下:

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

【问题讨论】:

    标签: sql sql-server tsql pivot unpivot


    【解决方案1】:

    为了将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。两个查询生成相同的结果。

    【讨论】:

    • 非常感谢 Bluefeet!只是想知道值列是否也可以采用其他值,例如日期。我有其他列,例如日期,我想做相同的数据透视,即 date_12-31-2012,但它给我一个错误,它与 UNPIVOT 列表中其他列的类型冲突
    • @ShivMady 您必须对任何不同数据类型的数据执行强制转换/转换。因此,您可能必须在 unpivot 之前使用子查询将数据转换为相同的类型。
    • Bluefeet:您能告诉我子查询的位置吗?抱歉这个愚蠢的问题。
    • @ShivMady 看到这个演示——sqlfiddle.com/#!3/30421/9。我添加了一个带有注释的子查询,您可以在其中进行转换
    • 嗨,Bluefeet,支点运行良好,但被告知我现在需要以下格式的数据:ID Expenses_2012 Revenue_2012 Expense_2011 Revenue_2011 1 2 3 Expense_2010 Revenue_2010。有特定的列,例如 YTDdate_03292013 包含 20121231,如果是,它应该在 2012 年填充它,如果是 2011,它应该在 2011 年填充它,但如果是 20120930,它不是年末,它应该填充在另一组标记为部分年份的列中并应规定放置 5 个部分日期。你认为我应该使用透视代码并解析它吗?
    猜你喜欢
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2013-02-09
    • 1970-01-01
    • 2016-11-17
    相关资源
    最近更新 更多