2016-04-05 1 views
3

日付の値に基づいて列ごとに最後の非NULL値を選択しようとしています。次の非NULL値を選択する方法各列に。 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` 

を私は、電子メールアドレスごとに各列の最新のnull以外の値を表示したいです。

出力する必要があります - 私はすでにこの問題を解決するためにいくつかのかなり醜いSQLを書かれている

Email   Name1 Name2 Job 
[email protected] Ron  Smith NULL 
[email protected] NULL Ford Plumber 

は、しかし、私はより多くの列を持つ別のテーブルに、このロジックを適用したいです。

私の質問です - 各列に参加することなくこれを行う簡単な方法はありますか?次のように

現在のソリューションがある - この場合に役立ちます

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

あなたはDISTINCTFIRST_VALUEを使用することができます。

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 
関連する問題