【问题标题】:Pivot table join in sqlsql中的数据透视表连接
【发布时间】:2026-01-03 08:40:01
【问题描述】:

我有表 Tbl_Login

Cat_ID 整数 金额 1 小数 金额 2 小数 金额 3 小数 日期日期 Cat_ID Amount1 Amount2 Amount3 日期 1 10 12 12 2013-02-12 2 10 12 12 2013-02-12 3 10 12 12 2013-02-12 4 10 12 12 2013-02-12 1 20 22 22 2013-02-13 2 20 22 22 2013-02-13 3 20 22 22 2013-02-13 5 20 22 22 2013-02-13 我想输入两个日期 12/02/2013 15/02/2013 和 列 1 Cat_ID 12-02-2013 13-02-2013 14-02-2013 15-02-2013 金额1 1 10 20 null null 金额 2 1 12 22 null null 金额 3 1 12 22 null null 金额1 2 10 20 null null 金额 2 2 12 22 null null 金额 3 2 12 22 null null 金额1 3 10 20 null null 金额2 3 12 22 null null 金额 3 3 12 22 null null 金额1 4 10 null null null 金额 2 4 12 null null null 金额 3 4 12 null null null 金额1 5 null 20 null null 金额 2 5 无 22 无 无 金额 3 5 无 22 无 无

【问题讨论】:

    标签: sql pivot-table


    【解决方案1】:

    您没有指定您使用的是什么 RDBMS,但是您可以通过多种方式将此数据转换为您需要的结果。

    如果您使用的数据库没有PIVOT 函数,则可以通过使用UNION ALL 查询来取消透视数据,然后使用带有CASE 表达式的聚合函数来透视数据。日期成列。查询将与此类似:

    select col, 
      cat_id,
      max(case when dateon = '2013-02-12' then value end) [2013-02-12],
      max(case when dateon = '2013-02-13' then value end) [2013-02-13],
      max(case when dateon = '2013-02-14' then value end) [2013-02-14],
      max(case when dateon = '2013-02-15' then value end) [2013-02-15]
    from
    (
      select cat_id, 'amount1' col, amount1 value, dateon
      from tbl_login
      where dateon >= '2013-02-12'
        and dateon <= '2013-02-15'
      union all
      select cat_id, 'amount2' col, cast(amount2 as decimal(10,2)) value, dateon
      from tbl_login
      where dateon >= '2013-02-12'
        and dateon <= '2013-02-15'
      union all
      select cat_id, 'amount3' col, cast(amount3 as decimal(10,2)) value, dateon
      from tbl_login
      where dateon >= '2013-02-12'
        and dateon <= '2013-02-15'
    ) src
    group by col, cat_id
    order by cat_id, col
    

    SQL Fiddle with Demo

    如果您使用的是 SQL Server 2005+ 或 Oracle 11g+,那么您可以同时使用 UNPIVOTPIVOT 函数:

    select col, cat_id,
      [2013-02-12], [2013-02-13], 
      [2013-02-14], [2013-02-15]
    from
    (
      select cat_id, dateon,
        col, value
      from
      (
        select cat_id, amount1, 
          cast(amount2 as decimal(10,2)) amount2, 
          cast(amount3 as decimal(10,2)) amount3, 
          dateon
        from tbl_login
        where dateon >= '2013-02-12'
          and dateon <= '2013-02-15'
      ) s
      unpivot
      (
        value
        for col in (Amount1, Amount2, Amount3)
      ) unpiv
    ) src
    pivot
    (
      max(value)
      for dateon in ([2013-02-12], [2013-02-13], 
                     [2013-02-14], [2013-02-15])
    ) piv
    order by cat_id, col
    

    SQL Fiddle with Demo

    如果您有未知数量的日期要转换为列,则可以使用动态 sql(注意:动态代码是 sql server 语法):

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX),
        @startdate datetime,
        @enddate datetime
    
    set @startdate  ='2013-02-12'
    set @enddate  ='2013-02-15'
    
    ;with dates (dt) as
    (
      select @startdate
      union all
      select dateadd(dd, 1, dt)
      from dates
      where dateadd(dd, 1, dt) <= @enddate
    )
    select dt
    into #temp
    from dates
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(varchar(10), dt, 120)) 
                        from #temp
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT col, cat_id,' + @cols + ' 
                from
                (
                  select cat_id, dateon,
                    col, value
                  from
                  (
                    select cat_id, amount1, 
                      cast(amount2 as decimal(10,2)) amount2, 
                      cast(amount3 as decimal(10,2)) amount3, 
                      dateon
                    from tbl_login
                    where dateon >= '''+convert(varchar(10), @startdate, 120)+'''
                      and dateon <= '''+convert(varchar(10), @enddate, 120)+'''
                  ) s
                  unpivot
                  (
                    value
                    for col in (Amount1, Amount2, Amount3)
                  ) unpiv
                ) src
                pivot
                (
                  max(value)
                  for dateon in (' + @cols + ')
                ) p 
                order by cat_id, col'
    
    execute(@query)
    

    SQL Fiddle with Demo

    所有查询的结果是:

    |     COL | CAT_ID | 2013-02-12 | 2013-02-13 | 2013-02-14 | 2013-02-15 |
    ------------------------------------------------------------------------
    | amount1 |      1 |         10 |         20 |     (null) |     (null) |
    | amount2 |      1 |         12 |         22 |     (null) |     (null) |
    | amount3 |      1 |         12 |         22 |     (null) |     (null) |
    | amount1 |      2 |         10 |         20 |     (null) |     (null) |
    | amount2 |      2 |         12 |         22 |     (null) |     (null) |
    | amount3 |      2 |         12 |         22 |     (null) |     (null) |
    | amount1 |      3 |         10 |         20 |     (null) |     (null) |
    | amount2 |      3 |         12 |         22 |     (null) |     (null) |
    | amount3 |      3 |         12 |         22 |     (null) |     (null) |
    | amount1 |      4 |         10 |     (null) |     (null) |     (null) |
    | amount2 |      4 |         12 |     (null) |     (null) |     (null) |
    | amount3 |      4 |         12 |     (null) |     (null) |     (null) |
    | amount1 |      5 |     (null) |         20 |     (null) |     (null) |
    | amount2 |      5 |     (null) |         22 |     (null) |     (null) |
    | amount3 |      5 |     (null) |         22 |     (null) |     (null) |
    

    【讨论】:

    • “amount1”列的类型与UNPIVOT列表中指定的其他列的类型冲突。
    • 这些列的数据类型是什么?如果是十进制,精度和长度是多少?
    • amount1 decimal(10,2),amount1 smallint
    • amount1 如何有两种不同的数据类型?您的 OP 将它们全部显示为 decimal?
    • @AnilDiggiwal 那么,它是哪一个?amount1 是小数还是小数?如果不是decimal,那么您应该使用正确的信息更新您的问题