【问题标题】:SQL - Combine multiple rows into single row with dynamic number of columnsSQL - 将多行组合成具有动态列数的单行
【发布时间】:2015-11-11 17:03:39
【问题描述】:

我正在尝试设置一个查询,该查询从表中选择多行并将相似的行组合成具有多列的单行。我相信我可以使用枢轴来做到这一点,但是每一行的列数不会相同,这就是我遇到问题的地方。我在下面举了一个例子来说明我的意思。

这个:

Account    Period    Amount
01         0001      1111
01         0002      2222
01         0003      3333
02         0001      1111
03         0001      1111
04         0001      1111
04         0002      2222

应该是这样的:

Account    0001    0002   0003   
01         1111    2222   3333
02         1111      
03         1111
04         1111    2222

这是我的初始查询,它将所有数据放在一起:

    WITH CTE AS(

    SELECT
      a.Period, a.Account, SUM(a.Amount) Amount
    FROM
      LedgerAP a
    WHERE
      a.Period >= 201500
    GROUP BY a.Period, a.Account

    UNION

    SELECT 
      b.Period, b.Account, SUM(b.Amount) Amount
    FROM
      LedgerAR b
    WHERE
      b.Period >= 201500
    GROUP BY b.Period, b.Account

    UNION

    SELECT
      c.Period, c.Account, SUM(c.Amount)
    FROM
      LedgerEx c
    WHERE
      c.Period >= 201500
    GROUP BY c.Period, c.Account

    UNION

    SELECT
      d.Period, d.Account, SUM(d.Amount)
    FROM
      LedgerMisc d
    WHERE
      d.Period >= 201500
    GROUP BY d.Period, d.Account

    )

    SELECT account,
           max(case when period = @Budgetyear + '01' then SUM(amount) end) Amount1,
           max(case when period = @Budgetyear + '02' then SUM(amount) end) Amount2,
           max(case when period = @Budgetyear + '03' then SUM(amount) end) Amount3,
           max(case when period = @Budgetyear + '04' then SUM(amount) end) Amount4,
           max(case when period = @Budgetyear + '05' then SUM(amount) end) Amount5,
           max(case when period = @Budgetyear + '06' then SUM(amount) end) Amount6,
           max(case when period = @Budgetyear + '07' then SUM(amount) end) Amount7,
           max(case when period = @Budgetyear + '08' then SUM(amount) end) Amount8,
           max(case when period = @Budgetyear + '09' then SUM(amount) end) Amount9,
           max(case when period = @Budgetyear + '10' then SUM(amount) end) Amount10,
           max(case when period = @Budgetyear + '11' then SUM(amount) end) Amount11,
           max(case when period = @Budgetyear + '12' then SUM(amount) end) Amount12

FROM CTE
GROUP BY account
ORDER BY account ASC

现在我该如何像上面展示的那样组织这个?任何帮助都会很棒!

【问题讨论】:

  • 动态 PIVOT,附加列将有 NULL
  • 我编辑了帖子以显示我正在尝试的当前方式,但我在聚合中有一个聚合,所以它不喜欢它

标签: sql sql-server pivot


【解决方案1】:

感谢@Bluefeet's solution here,您可以像这样构建动态枢轴:

create table table1 (Account varchar(2), Period varchar(4), Amount int)

insert into table1 values
('01', '0001', 1111),
('01', '0002', 2222),
('01', '0003', 3333),
('02', '0001', 1111),
('03', '0001', 1111),
('04', '0001', 1111),
('04', '0002', 2222);

动态查询:

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

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(t.period) 
            FROM table1 t
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Account, ' + @cols + ' from 
            (
                select Account
                    , Period
                    , Amount
                from table1
           ) x
            pivot 
            (
                 max(amount)
                for period in (' + @cols + ')
            ) p '


execute(@query)
GO

结果:

+---------+------+--------+--------+
| Account | 0001 |  0002  |  0003  |
+---------+------+--------+--------+
|      01 | 1111 | 2222   | 3333   |
|      02 | 1111 | (null) | (null) |
|      03 | 1111 | (null) | (null) |
|      04 | 1111 | 2222   | (null) |
+---------+------+--------+--------+

SQL Fiddle Demo

【讨论】:

    【解决方案2】:

    你的基本支点:

    SELECT
    SUM(case Period when '0001' then Amount end) as '0001',
    SUM(case Period when '0002' then Amount end) as '0002',
    SUM(case Period when '0003' then Amount end) as '0003'
    FROM LedgerAP
    GROUP BY Account
    

    动态创建该查询,如果您有多个 Period 值,这将很有帮助:

    DECLARE @SQL varchar(max) = 'SELECT '
    ;WITH Periods AS
    (
    SELECT DISTINCT Period
    FROM LedgerAP
    )
    SELECT @SQL = @SQL + 
        'SUM(case Period when ''' + Period + ''' then Amount end) as ''' + Period + ''','
    
    SET @SQL = LEFT(@SQL,LEN(@SQL) - 1) + ' FROM LedgerAP GROUP BY Account'
    EXEC(@SQL)
    

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 2013-12-31
      • 2014-03-08
      • 1970-01-01
      • 2020-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多