我试图根据日期值选择每列的最后一个非空值。
我有一张看起来像这样的表 -
Email Name1 Name2 Job Date
Test1@test.com Ron NULL NULL 2015-01-01 00:00:00.000
Test1@test.com Dave Smith NULL 2014-01-01 00:00:00.000
Test1@test.com NULL NULL NULL 2013-01-01 00:00:00.000
Test2@test.com NULL Smith NULL 2014-01-01 00:00:00.000
Test2@test.com NULL Ford Plumber 2015-01-01 00:00:00.000`
我想为每个电子邮件地址显示每列的最新非空值。
输出应为 -
Email Name1 Name2 Job
Test1@test.com Ron Smith NULL
Test2@test.com NULL Ford Plumber
我已经编写了一些非常难看的SQL来解决这个问题但是我想将这个逻辑应用到另一个包含更多列的表中。
我的问题是 - 是否有更简单的方法来执行此操作而无需为每列加入?
目前的解决方案如下 -
select distinct a.[Email],b.[Name1],c.[Name2],d.[job] from
(
select [Email] from #test
)
A
left join
(
SELECT [Email],
FIRST_VALUE([Name1]) over(partition by [Email] order by [Date] desc) as [Name1]
from #test
where [Name1] is not null
) b
on a.[Email] = b.[Email]
left join
(
SELECT [Email],
FIRST_VALUE([Name2]) over(partition by [Email] order by [Date] desc) as [Name2]
from #test
where [Name2] is not null
) c
on a.[Email] = c.[Email]
left join
(
select [Email],
FIRST_VALUE([Job]) over(partition by [Email] order by [Date] desc) as [Job]
from #test
where [Job] is not null
) d
on a.[Email] = d.[Email]
如果有帮助的话,这里是示例表的DDL / DML -
create table #test
([Email] nvarchar(50),
[Name1] nvarchar(50),
[Name2] nvarchar(50),
[Job] nvarchar(50),
[Date] datetime)
insert into #test
values
('Test1@test.com', 'Ron', null,null,'20150101'),
('Test1@test.com', 'Dave' ,'Smith',null, '20140101'),
('Test1@test.com', null, null, null ,'20130101'),
('Test2@test.com', null, 'Smith', null, '20140101'),
('Test2@test.com', null, 'Ford', 'Plumber','20150101')
答案 0 :(得分:3)
有些方法不需要这么多连接。没有一个是简单的,因为SQL Server不支持ignore nulls
上的lag()
选项。
基本上,您需要在每列上执行逻辑操作。没有子查询的一种方法是:
select distinct email,
first_value(name1) over (partition by email
order by (case when name1 is not null then date else '2000-01-01' end) desc
) as name1,
. . .
from #test;
另一种选择使用外部申请:
select t.email, name1, . . .
from (select distinct email from #test t) t outer apply
(select top 1 name1
from #test t2
where t2.email = t.email and name1 is not null
order by date desc
) name1 . . .
答案 1 :(得分:2)
您可以将FIRST_VALUE
与DISTINCT
:
SELECT DISTINCT Email,
FIRST_VALUE(Name1) OVER (PARTITION BY Email
ORDER BY CASE
WHEN Name1 IS NULL THEN '19000101'
ELSE [Date]
END DESC) AS Name1,
FIRST_VALUE(Name2) OVER (PARTITION BY Email
ORDER BY CASE
WHEN Name2 IS NULL THEN '19000101'
ELSE [Date]
END DESC) AS Name2,
FIRST_VALUE(Job) OVER (PARTITION BY Email
ORDER BY CASE
WHEN Job IS NULL THEN '19000101'
ELSE [Date]
END DESC) AS Job
FROM test