sqlserver - 使用 pivot 将多行合并为一行

sqlserver - combine multiple rows into one rows by using pivot

假设我们有以下 table:

ID      Type    Amount
0001     A       10
0001     B       20
0001     C       30
0002     A       15
0002     C       20
0003     B       40
...

期望的结果将是:

ID      Type A   Type B    Type C 
0001     10       20        30

为了将多行合并为一行,我可以执行以下操作。

SELECT ID, A, B, C
FROM  MyTable 
PIVOT
(
      SUM(amount)
       FOR Type IN (A, B, C)
) AS P

然而,我的 table 比前一个更复杂。 假设我的 table 如下:

ID      Type    Total_Amount   Average_Amount
0001     A       10                0.5
0001     B       20                0.7
0001     C       30                0.9

所以我的问题是如何产生以下结果?

ID      TypeA_total  TypeB_total   TypeC_total TypeA_avg  TypeB_avg   TypeC_avg 
0001     10           20              30        0.5         0.7          0.9

更新:

  1. 类型数量固定。这意味着只有类型 A、B 和 C。 有些 ID 可能只有一种类型。有些可能具有所有 3 种类型。其他一些可能有2种。

  2. Total_amount和Average_amount在原文中给出table。我不需要计算。

这里是 link,你可以用 table 玩: http://sqlfiddle.com/#!3/4e6835

您需要unpivot之前的数据pivoting

WITH cte 
     AS (SELECT id, 
                value, 
                col_name 
         FROM   yourtable 
                CROSS apply( VALUES (total_amount,'Type' + type + '_Total'), 
                                    (average_amount,'Type' + type + '_Avg') ) 
             CS (value, col_name)) 
SELECT * 
FROM   cte 
       PIVOT (Max(value) 
             FOR col_name IN([TypeA_total],[TypeB_total],[TypeC_total], 
                             [TypeA_avg],[TypeB_avg],[TypeC_avg]))pv 

注:如果没有。的 types 是未知的,那么你需要使用 dynamic sql

这是另一种方法。这是使用交叉表查询而不是 PIVOT。我发现语法不那么迟钝,甚至比使用 PIVOT 有轻微的性能提升。

if OBJECT_ID('tempdb..#something') is not null
    drop table #something

create table #something
(
    ID char(4)
    , SomeType char(1)
    , Amount int
    , AverageAmount decimal(9, 2)
)

insert #something
select '0001', 'A', 10, .5 union all
select '0001', 'B', 20, .7 union all
select '0001', 'C', 30, .9;

with OrderedResults as
(
    select *
        , ROW_NUMBER() over(partition by ID order by SomeType) as RowNum
    from #something
)

select ID
    , MAX(Case when RowNum = 1 then SomeType end) as TypeA
    , MAX(Case when RowNum = 1 then AverageAmount end) as AverageA
    , MAX(Case when RowNum = 2 then SomeType end) as TypeB
    , MAX(Case when RowNum = 2 then AverageAmount end) as AverageB
    , MAX(Case when RowNum = 3 then SomeType end) as TypeC
    , MAX(Case when RowNum = 3 then AverageAmount end) as AverageC
from OrderedResults
group by ID