如何将非空数据行合并为一个

时间:2014-11-10 23:24:26

标签: sql-server tsql

我需要合并数据行,例如:

pid   seq   str1    str2    str3
1     1     NULL    mary    NULL
1     2     jim     craig   NULL
1     3     kevin   NULL    NULL
2     1    david    NULL    NULL
2     2    NULL     annie   NULL

应该成为:

pid str1    str2    str3
1   kevin   craig   NULL
2   david   annie   NULL

以下工作,但非常慢,因为所涉及的表有大约1/2百万行,并且有30列可供操作。

select pid,                             
(select top 1 p1.str1 from mytable p1 where p1.pid=p2.pid and p1.str1 is not null order by seq desc),
(select top 1 p1.str2 from mytable p1 where p1.pid=p2.pid and p1.str2 is not null order by seq desc),
(select top 1 p1.str3 from mytable p1 where p1.pid=p2.pid and p1.str3 is not null order by seq desc),
...
from mytable p2
group by pid

我在网上看过使用FOR XML PATH()的文章。但由于这也涉及到如上所述的选择查询,我认为它的表现要好得多。 (如果我错了,请纠正我。)

请帮忙。感谢。

1 个答案:

答案 0 :(得分:0)

尝试使用ROW_NUMBER()

create table temp(
    pid int,
    seq int,
    str1 varchar(50),
    str2 varchar(50),
    str3 varchar(50)
)
insert into temp
select 1, 1, NULL, 'mary', NULL union all 
select 1, 2, 'jim', 'craig', NULL union all 
select 1, 3, 'kevin', NULL, NULL union all 
select 2, 1, 'david', NULL, NULL union all 
select 2, 2, NULL, 'annie', NULL


;with cte as(
    select 
        *,
        rn1 = row_number() over (partition by pid order by case when str1 is not null then seq else 0 end desc),
        rn2 = row_number() over (partition by pid order by case when str2 is not null then seq else 0 end desc),
        rn3 = row_number() over (partition by pid order by case when str3 is not null then seq else 0 end desc)
    from temp
)
select
    pid,
    str1 = max(case when rn1 = 1 then str1 end),
    str2 = max(case when rn2 = 1 then str2 end),
    str3 = max(case when rn3 = 1 then str3 end)
from cte
group by pid

drop table temp