2016-04-05 2 views
3

Я пытаюсь выбрать последнее ненулевое значение для каждого столбца на основе значения даты.Как выбрать следующее ненулевое значение В каждом столбце. T-SQL

У меня есть таблица, которая выглядит следующим образом -

Email   Name1 Name2 Job  Date 
[email protected] Ron  NULL NULL 2015-01-01 00:00:00.000 
[email protected] Dave Smith NULL 2014-01-01 00:00:00.000 
[email protected] NULL NULL NULL 2013-01-01 00:00:00.000 
[email protected] NULL Smith NULL 2014-01-01 00:00:00.000 
[email protected] NULL Ford Plumber 2015-01-01 00:00:00.000` 

Я хочу, чтобы отобразить новейшее ненулевое значение для каждого столбца на адрес электронной почты.

Выход должен быть -

Email   Name1 Name2 Job 
[email protected] Ron  Smith NULL 
[email protected] 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 
('[email protected]', 'Ron', null,null,'20150101'), 
('[email protected]', 'Dave' ,'Smith',null, '20140101'), 
('[email protected]', null, null, null ,'20130101'), 
('[email protected]', null, 'Smith', null, '20140101'), 
('[email protected]', null, 'Ford', 'Plumber','20150101') 

ответ

2

Есть способы, которым не требуется так много объединений. Нет, это просто, потому что 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 . . . 
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 
Смежные вопросы