SQL - 将多行组合为具有动态列数的单行

时间:2015-11-11 17:03:40

标签: sql sql-server pivot

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

此:

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

现在我怎样才能像上面所示那样组织这个?任何帮助都会很棒!

2 个答案:

答案 0 :(得分:0)

归功于@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

答案 1 :(得分:-1)

您的基本支点:

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)