sql - 如何在每列中选择下一个非空值。 T-SQL

标签 sql sql-server sql-server-2012

我尝试根据日期值选择每列的最后一个非空值。

我有一个看起来像这样的表格 -

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')

最佳答案

有一些方法不需要那么多连接。没有一个是简单的,因为 SQL Server 不支持 lag() 上的ignore nulls 选项。

基本上,您需要对每一列进行逻辑处理。一种没有子查询的方法是:

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 . . .

关于sql - 如何在每列中选择下一个非空值。 T-SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36428530/

相关文章:

sql - 在数据库级别创建用户

sql - SSIS/SQL Server - 处理各种货币类型符号

sql - SQL 中的 ddmmyyyy 到 sql 日期时间

sql - SparkSQL支持子查询吗?

sql-server - sql server 中的 CASE - 实现澄清?

sql - 为什么要在字段上使用LEFT JOIN然后在以后的WHERE子句中将其过滤掉?

sql-server - 将 XML 节点转换为 SQL Server 中的行

sql-server - 在触发器中查找多个更新的列

sql-server - 存储过程中的删除表无法正常工作?

sql-server - SQL Server 2012 消耗太多网络流量来获取所有数据