Sql 对动态列中的值进行分组

Sql 对动态列中的值进行分组,sql,sql-server,select,grouping,Sql,Sql Server,Select,Grouping,我有两个数据表 表1 表2 我需要一个查询,它将产生 表3 TAB1包含用户和ID。TAB2包含动态结构中的列和值。如果一个单元格(请参见[TAB2.NAME='C1'和TAB2.ID1=1])有多个值,则应采用与ROOT='A'关联的值 我唯一的问题是如何根据根列选择正确的值。以下代码返回TAB3的正确结构,但值不正确 select t.id1, t.id2, t.a, max(case when t2.name = 'C2' then t2.vint end) c2, max

我有两个数据表

表1

表2

我需要一个查询,它将产生

表3

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

我唯一的问题是如何根据根列选择正确的值。以下代码返回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
理想情况下,我希望有一个没有子查询的单一查询


我设法通过子查询来解决这个问题,但解决方案太慢了。上面的例子是本文的后续部分。(注:真实模型几乎有100个动态列)

听起来,对于
name,id1
的每个组合,您只需要一行
tab2
row\u 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

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

当我运行您的查询时,我感到困惑,我得到了上面的结果()结果出了什么问题?它应该显示什么?你是对的。我将“0”与“O”混合。我修复了post和您的SQLFIDLE。谢谢,这看起来很有趣,但我有多达100列(如“C1”)和20根(如“A”、“B”)。我可以应用你的解决方案吗?@orwe。引用OP的话:“我唯一的问题是如何从根列中提取正确的值。”您是否在尝试解决其他问题?
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
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
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