noa*_*ahC 5 sql t-sql sql-server sql-server-2008-r2
给定2个或更多行选择合并,其中一行被识别为模板行.其他行应将其数据合并到模板具有的任何空值列中.
示例数据:
Id Name Address City State Active Email Date
1 Acme1 NULL NULL NULL NULL blah@yada.com 3/1/2011
2 Acme1 1234 Abc Rd Springfield OR 0 blah@gmail.com 1/12/2012
3 Acme2 NULL NULL NULL 1 blah@yahoo.com 4/19/2012
Run Code Online (Sandbox Code Playgroud)
假设用户选择了Id 1作为模板行的行,而Ids 2和3的行将合并到行1中然后删除.行Id 1中的任何空值列应填充(如果存在)最近的(请参见日期列)非空值,并且行Id 1中已存在的非空值将保持原样.对上述数据的查询结果应该是这样的:
Id Name Address City State Active Email Date
1 Acme1 1234 Abc Road Springfield OR 1 blah@yada.com 3/1/2011
Run Code Online (Sandbox Code Playgroud)
请注意,Active值为1,而不是0,因为行Id 3具有最新日期.
PS此外,有没有任何方法可以做到这一点,而无需事先明确定义/知道所有列名称是什么?我正在使用的实际表格有很多列,新的列一直在添加.有没有办法查找表中的所有列名,然后使用该子查询或temptable来完成这项工作?
您可以通过首先按模板标志对行进行排序,然后按日期描述来进行排序。模板行应始终是最后一行。每行都按该顺序分配一个编号。使用 max() 我们找到第一个占用的单元格(按数字降序排列)。然后我们从与这些最大值匹配的行中选择列。
; with rows as (
select test.*,
-- Template row must be last - how do you decide which one is template row?
-- In this case template row is the one with id = 1
row_number() over (order by case when id = 1 then 1 else 0 end,
date) rn
from test
-- Your list of rows to merge goes here
-- where id in ( ... )
),
-- Finding first occupied row per column
positions as (
select
max (case when Name is not null then rn else 0 end) NamePosition,
max (case when Address is not null then rn else 0 end) AddressPosition,
max (case when City is not null then rn else 0 end) CityPosition,
max (case when State is not null then rn else 0 end) StatePosition,
max (case when Active is not null then rn else 0 end) ActivePosition,
max (case when Email is not null then rn else 0 end) EmailPosition,
max (case when Date is not null then rn else 0 end) DatePosition
from rows
)
-- Finally join this columns in one row
select
(select Name from rows cross join Positions where rn = NamePosition) name,
(select Address from rows cross join Positions where rn = AddressPosition) Address,
(select City from rows cross join Positions where rn = CityPosition) City,
(select State from rows cross join Positions where rn = StatePosition) State,
(select Active from rows cross join Positions where rn = ActivePosition) Active,
(select Email from rows cross join Positions where rn = EmailPosition) Email,
(select Date from rows cross join Positions where rn = DatePosition) Date
from test
-- Any id will suffice, or even DISTINCT
where id = 1
Run Code Online (Sandbox Code Playgroud)
编辑:
上一节中的交叉联接实际上可能是 rows.rn = xxxPosition 上的内部联接。它以这种方式工作,但更改为内部联接将是一个改进。