获取日期不为null的先前记录-SQL SERVER

时间:2018-10-17 07:09:21

标签: sql sql-server tsql common-table-expression

我有两个表格,如下所示:

表1:

ID  B   C   D   E   Date

1   b   c   D   E   2018/10/10
1   c   d   A   B   2018/10/14

表2:

ID  B   C   Date
1   b   c   2018/10/10
1   x   y   2018/10/11
1   y   x   2018/10/12
1   p   q   2018/10/13
1   c   d   2018/10/14

表A有6列,而表2有4列。 使用左联接的结果是:

Select * from Table2 t2 left join table1 t1
on t2.id=t1.id and t2.Date = t1.Date

左加入结果为:

ID  B   C   D   E   Date1           ID  B   C   Date2

1   b   c   D   E   2018/10/10      1   b   c   2018/10/10
-   -   -   -   -   -               1   x   y   2018/10/11
-   -   -   -   -   -               1   y   x   2018/10/12
    -   -   -   -   -               1   p   q   2018/10/13
1   c   d   A   B   2018/10/14      1   c   d   2018/10/14

注意:

  1. '-'表示NULL。

  2. 日期按左连接结果排序-按table2.date排序, table1.date asc

  3. 我接受了加入cte的结果。不能够 产生最终结果。

预期结果:

ID  B   C   D   E   Date

1   b   c   D   E   2018/10/10
1   x   y   D   E   2018/10/11
1   y   x   D   E   2018/10/12
1   p   q   D   E   2018/10/13
1   c   d   A   B   2018/10/14

如果左联接结果中table1的Date为null,则搜索表1的先前非null日期,该日期将小于表2的当前日期。

然后从那里获取D和E列的值,并从Date1为空的当前记录中保留B和C列的值。

作为sql的新手,我陷入了困境。请帮忙。

谢谢。

4 个答案:

答案 0 :(得分:1)

如果您使用的是SQL Server 2012或更高版本,则以下查询将返回所需的值。我使用过CTEfirst_value()函数,并且查询已优化

with
    cte
as
(
    select
        t2.ID   ,
        t2.B    ,
        t2.C    ,
        t1.D    ,
        t1.E    ,
        t2.[Date]   ,
        sum(case when t1.D is null then 0 else 1 end) over (order by t2.[Date]) as D_partition,
        sum(case when t1.E is null then 0 else 1 end) over (order by t2.[Date]) as E_partition
    from
        Table2 t2
    left join
        table1 t1
    on
        t2.id = t1.id
        and
            t2.[Date] = t1.[Date]
)
select
    cte.ID  ,
    cte.B   ,
    cte.C   ,
    first_value(D) over(partition by D_partition order by D desc)   as D    ,
    first_value(E) over(partition by E_partition order by E desc)   as E    ,
    cte.Date
from
    cte;

答案 1 :(得分:1)

使用外部申请排名第一。它会给您带来快速而简短的结果:

-- create data from example:
-- ------------------------
select * into #Table1 from
(select 1 as ID, 'b' as B, 'c' as C, 'D' as D, 'E' as E, cast('2018-10-10' as date) as [Date]
union all select 1,   'c',   'd',   'A',   'B',   '2018-10-14')t

select * into #Table2 from
(select 1 as ID,   'b' as B,   'c' as C ,   cast('2018-10-10' as date) as [Date]
union all select 1,   'x',   'y',   '2018-10-11'
union all select 1,   'y',   'x',  '2018-10-12'
union all select 1,   'p',   'q',   '2018-10-13'
union all select 1,   'c',   'd',   '2018-10-14')t

-- SOLUTION
-- -------- 
select
    T2.ID,
    T2.B,
    T2.C,
    T1.D,
    T1.E,
    T2.[Date]
from
    #Table2 T2
    outer apply
    (
        select top 1 * from #Table1 T1
        where T1.ID=T2.ID and T1.[Date] <= T2.[Date]
        order by T1.[Date] desc
    ) T1


-- clean everything
-- ----------------
drop table #Table1
drop table #Table2

答案 2 :(得分:0)

似乎您将table2连接到表1,并且想要table1的值(如果存在),否则想要来自table2的值。数据级别的“ if”通常是通过CASE函数实现的。但是,根据您的情况,我们可以使用更具体的函数ISNULL(a,b),当a具有值时返回a,而当a为空时返回b:

select 
    t2.ID,
    isnull(t1.B,t2.B) as B,
    isnull(t1.C,t2.C) as C,
    isnull(t1.D,t2.D) as D,
    isnull(t1.E,t2.E) as E,
    isnull(t1.[Date],t2.[Date]) as [Date]
from Table2 t2 
left join table1 t1
on t2.id=t1.id and t2.Date = t1.Date

但是,您确定需要t2.Date = t1.Date吗?通常,名为ID的列是唯一/主键,因此这将使日期的附加联接条件变得多余。在这种情况下,您应该删除它。

答案 3 :(得分:0)

您可以检查一下是否在寻找以下内容吗?

Select t2.ID,t2.B,t2.C,t1.D,t1.E, t2.Date from Table2 t2 left join table1 t1
on t2.id=t1.id and (t2.Date >= t1.Date)
where not exists (select 1 from table1 t12 where t2.Date > t1.Date and t2.Date >= t12.Date and t12.Date > t1.Date)

在这里,我们尝试两次打开表1(t1和t12),以确保表2中的日期必须> =表1中的日期而<其他日期。