从动态列分组值

时间:2013-06-05 23:42:07

标签: sql sql-server select grouping

我有两个数据表

TAB1

    -------------------------
    | ID1 | ID2 |  A    | B |
    |  1  |  8  |'John' | 9 |
    |  2  |  9  |'Smith'| 0 |

TAB2

   ------------------------------------------
   | NAME | ID1 | ID2 | VSTRING | VINT |ROOT|
   | 'C1' |  1  |  8  |  'R01'  | NULL | 'A'|
   | 'C1' |  1  |  8  |  'R02'  | NULL | 'B'|
   | 'C2' |  1  |  8  |   NULL  | 9991 | 'B'|
   | 'C1' |  2  |  9  |  'D02'  | NULL | 'B'|

我需要一个会产生

的查询

TAB3

    -------------------------------------
    | ID1 | ID2 |   A    |  C1   |  C2  | 
    |  1  |  8  | 'John' | 'R01' | 9991 | 
    |  2  |  9  | 'Smith'| 'D02' | NULL |

TAB1包含用户和ID。 TAB2包含动态结构中的列和值。如果一个单元格(参见[TAB2.NAME ='C1'和TAB2.ID1 = 1])具有多个值,则应采用与ROOT ='A'关联的值。

我唯一的问题是如何在ROOT列上获取正确的值。以下代码返回TAB3的正确结构,但值不正确。

select t.id1, t.id2, t.a,
    max(case when t2.name = 'C2' then t2.vint end) c2,
    max(case when t2.name = 'C1' then t2.vstring end) c1
from tab1 t
    left join tab2 t2 on t.id1 = t2.id1 and t.id2 = t2.id2 
group by t.id1, t.id2, t.a

理想情况下,我希望只有一个没有子查询的查询。

我设法通过子查询来解决这个问题,但解决方案太慢了。以上示例是Pivot on joined tables SQL Server的后续行动。 (PS:真实模型有近100个动态列)

2 个答案:

答案 0 :(得分:0)

对于tab2的每个组合,您似乎只想要一行name, id1row_number()功能可以为您完成此操作。它为每个这样的组分配一个序列。对于您的查询,此序列从root = 'A'所在的行(如果有)开始。

完整查询与您的类似,但tab2替换为子查询,on条件略有修改:

select t.id1, t.id2, t.a,
    max(case when t2.name = 'C2' then t2.vint end) c2,
    max(case when t2.name = 'C1' then t2.vstring end) c1
from tab1 t left join
     (select t2.*,
             row_number() over (partition by name, id1
                                order by (case when root = 'A' then 1 else 0 end) desc
                               ) as seqnum
      from tab2 t2
     ) t2
     on t.id1 = t2.id1 and
        t.id2 = t2.id2 and
        t2.seqnum = 1
group by t.id1, t.id2, t.a

答案 1 :(得分:0)

Gordon Linoff你的回答是正确的,但我没有办法让它变得更有活力。幸运的是,我发现了一个非常通用的解关键是将TAB1与分组的TAB2连接起来。

Select * from TAB2 A join 
   (Select ID1, ID2, MIN(ROOT), NAME from TAB2 
       group by ID2, ID1, NAME) B
   on A.ID1 = B.ID1 and B.ID2 = A.ID2 and A.NAME = B.NAME