尝试在特定条件下将行合并为一行

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来完成这项工作?

Nik*_*vić 2

您可以通过首先按模板标志对行进行排序,然后按日期描述来进行排序。模板行应始终是最后一行。每行都按该顺序分配一个编号。使用 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)

你可以在 Sql Fiddle 上检查一下

编辑:

上一节中的交叉联接实际上可能是 rows.rn = xxxPosition 上的内部联接。它以这种方式工作,但更改为内部联接将是一个改进。