根据SQL中的ID选择最近的日期

时间:2017-09-11 09:11:42

标签: sql sql-server

我有两张表Dispense& Pro Table,我想从分配表中选择所有行,从Pro表中选择最近的发货日期。

分配表

ID       Dispense date  Row ID
604743   10/18/2016     1
604743   11/4/2016      2
604743   11/28/2016     3
604743   12/16/2016     4

专业表

ID       Shipment Date  Row ID
604743   11/1/2016      1
604743   11/19/2016     2
604743   11/21/2016     3
604743   11/28/2016     4
604743   12/13/2016     5

需要输出

ID       Dispense date  Pre Ship date
604743   10/18/2016     NULL 
604743   11/4/2016      11/1/2016
604743   11/28/2016     11/19/2016
604743   12/16/2016     12/13/2016

NULL的原因:因为少于10/18的分发日期在Pro Table中的发货日期没有最近的日期

1 个答案:

答案 0 :(得分:0)

我尝试了递归CTE,但他们并不是都在子查询中使用锚点。 因此,循环是我能做的最好的。

该脚本允许在同一日期使用多个Dispense或Pro,如果约束不允许,请参阅哪些部分可以抛出的注释。

--- Dispense_Date must not be unique
declare @Dispense table(
    ID int not null,
    Dispense_Date date not null,
    Row_ID int not null identity primary key
)
-- Shipment_Date must not be unique
declare @Pro table(
    ID int not null,
    Shipment_Date date not null,
    Row_ID int not null identity primary key
)
declare @Result table(
    ID int not null,
    Dispense_Date date not null,
    Dispense_Row_ID int not null unique,
    Shipment_Date date not null,
    Pro_Row_ID int not null unique,
    dayDiff int not null,
    Row_ID int not null identity primary key,
    iter int not null
)

insert into @Dispense(ID, Dispense_Date)
values  (604743, '10/18/2016'),
        (604743, '11/4/2016'),
        /* (604743, '11/26/2016'),
        (604743, '11/27/2016'),
        (604743, '11/27/2016'),
        (604743, '11/28/2016'), */
        (604743, '11/28/2016'),
        (604743, '12/16/2016')

insert into @Pro(ID, Shipment_Date)
values  (604743, '11/1/2016'),
        /* (604743, '11/16/2016'),
        (604743, '11/19/2016'), */
        (604743, '11/19/2016'),
        (604743, '11/21/2016'),
        (604743, '11/28/2016'),
        (604743, '12/13/2016')

declare @iter int = 0

while exists(
    select      1
    from        @Dispense Dispense
                inner join
                @Pro Pro
                on  Pro.ID = Dispense.ID
                    and
                    Pro.Shipment_Date < Dispense.Dispense_Date
    where       not exists(
                    select      1
                    from        @Result Result
                    where       Result.Dispense_Row_ID = Dispense.Row_ID
                                or
                                Result.Pro_Row_ID = Pro.Row_ID
                )
)
begin
    set @iter = @iter + 1
    ;   
    with distance(
        ID, Dispense_Row_ID, Dispense_Date, Pro_Row_ID, Shipment_Date, dayDiff
    ) as(
        select      Dispense.ID,
                    Dispense.Row_ID Dispense_Row_ID,
                    Dispense.Dispense_Date,
                    Pro.Row_ID Pro_Row_ID,
                    Pro.Shipment_Date,
                    DATEDIFF(DAY, Pro.Shipment_Date, Dispense.Dispense_Date) dayDiff
        from        @Dispense Dispense
                    inner join
                    @Pro Pro
                    on  Pro.ID = Dispense.ID
                        and
                        Pro.Shipment_Date < Dispense.Dispense_Date
        where       not exists(
                        select      1
                        from        @Result Result
                        where       Result.Dispense_Row_ID = Dispense.Row_ID
                                    or
                                    Result.Pro_Row_ID = Pro.Row_ID
                    )

    )

    insert into @Result(ID, Dispense_Row_ID, Dispense_Date, Pro_Row_ID, Shipment_Date, daydiff, iter)
    select      Dispense.ID,
                Dispense.Row_ID Dispense_Row_ID,
                Dispense.Dispense_Date,
                distance.Pro_Row_ID,
                distance.Shipment_Date,
                distance.dayDiff,
                @iter
    from        @Dispense Dispense
                inner join
                distance
                on  distance.Dispense_Row_ID = Dispense.Row_ID
                    and
                    not exists(
                        select      1
                        from        distance dtExists
                        where       dtExists.ID = distance.ID
                                    and
                                    dtExists.Shipment_Date = distance.Shipment_Date
                                    and
                                    (
                                        dtExists.dayDiff < distance.dayDiff
                                        -- below OR not needed if Dispense_Date and Shipment_Date are unique
                                        or
                                        (
                                            dtExists.dayDiff = distance.dayDiff
                                            and
                                            (
                                                dtExists.Pro_Row_ID < distance.Pro_Row_ID
                                                or
                                                (
                                                    dtExists.Pro_Row_ID = distance.Pro_Row_ID
                                                    and
                                                    dtExists.Dispense_Row_ID < distance.Dispense_Row_ID
                                                )
                                            )
                                        )
                                    )
                    )
                    and
                    not exists(
                        select      1
                        from        distance dtExists
                        where       dtExists.ID = distance.ID
                                    and
                                    dtExists.Dispense_Date = distance.Dispense_Date
                                    and
                                    (
                                        dtExists.dayDiff < distance.dayDiff
                                        -- below OR not needed if Dispense_Date and Shipment_Date are unique
                                        or
                                        (
                                            dtExists.dayDiff = distance.dayDiff
                                            and
                                            (
                                                dtExists.Pro_Row_ID < distance.Pro_Row_ID
                                                or
                                                (
                                                    dtExists.Pro_Row_ID = distance.Pro_Row_ID
                                                    and
                                                    dtExists.Dispense_Row_ID < distance.Dispense_Row_ID
                                                )
                                            )
                                        )
                                    )
                    )
end

select      Dispense.ID,
            Dispense.Row_ID Dispense_Row_ID,
            Dispense.Dispense_Date,
            Result.Pro_Row_ID,
            Result.Shipment_Date,
            Result.dayDiff,
            Result.iter
from        @Dispense Dispense
            left join
            @Result Result
            on  Result.Dispense_Row_ID = Dispense.Row_ID
order by    Dispense.ID,
            Dispense.Dispense_Date,
            Result.Shipment_Date,
            Result.Dispense_Row_ID,
            Result.Pro_Row_ID