2017-08-26 1 views
1

Ich muss @firstParty mit dem besten Übereinstimmungen von @thirdParty ausfüllen.SQL Server Beste Datum-Übereinstimmungen zwischen den Datensätzen

Damit ein Datensatz übereinstimmt, muss @firstParty.Registered innerhalb von 31 Tagen von @thirdParty.Registered sein.

Darüber hinaus kann kein Datensatz von @thirdParty mit mehr als einem Datensatz in @firstParty verknüpft werden.

Ich möchte dies so effizient wie möglich tun. Die SQL Server-Version ist 2008, daher können Funktionen, die danach eingeführt werden, nicht verwendet werden.

Dieser Beispielcode ist eine Vereinfachung des eigentlichen Code, die ich nicht schreiben kann:

declare @firstParty table 
(
    FirstPartyId integer identity, 
    Registered date, 

    MinThirdPartyId integer, 
    MinThirdPartyRegistered date 

); 

insert into @firstParty (Registered) 
values 
('1/1/2017'), ('2/1/2017'), ('3/1/2017'), ('4/1/2017'), ('5/1/2017'), ('6/1/2017'); 

/* 
dates in @firstParty and @thirdParty are not guaranteed to be unique 
in all scenarios 
*/ 

declare @thirdParty table 
(
    ThirdPartyId integer identity, 
    Registered date 
); 

insert into @thirdParty (Registered) 
values 
('03/02/2017'), ('04/30/2017'); 


declare @x integer = 1; 
while @x <= (select max(FirstPartyId) from @firstParty) begin 

    declare @MinRegistered date = null; 

    --get minimum third party date within 31 days of registered date, that hasn't been used 
    select 
     @MinRegistered = min(tp.Registered)  
    from 
     @firstParty fp 
     join @thirdParty tp on 
      fp.Registered between dateadd(d, -31, tp.Registered) and dateadd(d, 31, tp.Registered) 
     left join @firstParty used on tp.ThirdPartyId = used.MinThirdPartyId 
    where 
     fp.FirstPartyId = @x 
     and used.MinThirdPartyId is null; 

    declare @MinThirdPartyId integer = null; 

    --get earliest ID of third party record with @MinRegistered 
    select top 1 
     @MinThirdPartyId = tp.ThirdPartyId 
    from 
     @firstParty fp 
     join @thirdParty tp on 
      tp.Registered = @MinRegistered 
     left join @firstParty used on tp.ThirdPartyId = used.MinThirdPartyId 
    where 
     fp.FirstPartyId = @x 
     and used.MinThirdPartyId is null 
    order by 
     tp.Registered, 
     tp.ThirdPartyId; 


    update @firstParty 
    set 
     MinThirdPartyId = @MinThirdPartyId, 
     MinThirdPartyRegistered = @MinRegistered 
    where 
     FirstPartyId = @x; 


    set @x = @x + 1; 

end; 


select 
    fp.FirstPartyId, 
    fp.Registered, 
    fp.MinThirdPartyId, 
    fp.MinThirdPartyRegistered 
from 
    @firstParty fp; 

Hier die Ergebnisse sind, die ich will:

FirstPartyId Registered MinThirdPartyId MinThirdPartyRegistered 
------------ ---------- --------------- ----------------------- 
1   2017-01-01 NULL   NULL 
2   2017-02-01 NULL   NULL 
3   2017-03-01 1    2017-03-02 
4   2017-04-01 NULL   NULL 
5   2017-05-01 2    2017-04-30 
6   2017-06-01 NULL   NULL 

Ein Ansatz, der zuerst alle Spiele auffüllt und dann entfernt die nicht optimalen Übereinstimmungen nicht, denn wenn ein @ @ FirstPartys optimaler @ ThirdParty-Datensatz entfernt wird, könnte es einen anderen Datensatz in @thirdParty geben, der immer noch eine akzeptable Übereinstimmung ist.

Antwort

1

Vielleicht so etwas?

Beispiel

Select A.FirstPartyId 
     ,A.Registered 
     ,MinThirdPartyId = B.ThirdPartyId 
     ,MinThirdPartyRegistered = B.Registered 
From @firstParty A 
Left Join (
       Select B1.* 
         ,MinPartyID =B2.FirstPartyID 
       From @thirdParty B1 
       Cross Apply (
           Select Top 1 with ties * 
           From @firstParty 
           Where abs(DateDiff(DAY,B1.Registered,Registered))<=31 
           Order By abs(DateDiff(DAY,B1.Registered,Registered)) 
          ) B2 
      ) B 
    on (B.MinPartyID=A.FirstPartyId) 

Returns

enter image description here

+0

perfekt funktioniert. Vielen Dank! –

+0

@BenOsborne Glücklich zu helfen –

Verwandte Themen