2017-09-15 2 views
0

Je vais commencer par dire que ce problème est similaire à SQL Join on Nearest Less Than Date mais que la solution ne fonctionne pas pour mon problème. Au lieu de sélectionner une seule colonne, j'ai besoin des résultats d'une table qui est «filtrée» en fonction de la date la plus proche.SQL Trouver Date d'entrée la plus proche dans le tableau correspondant

J'ai trois tables. La table principale contient des données de ticket de temps sous la forme:

ticketId 
ticketNumber 
ticketDate 
projectId 

Une table secondaire suit les plannings de taux pour les ressources sur chaque ticket quotidien du projet. Cela ressemble à ceci:

scheduleId 
projectId 
effectiveDate 

Il existe également une troisième table liée à la seconde qui contient effectivement les débits applicables. Quelque chose comme ceci:

scheduleId 
straightTime 
overTime 

Rejoindre les deux premières tables sur projectId (évidemment) réplique les données pour chaque enregistrement dans le calendrier de tarifs pour le projet. Si j'ai 3 grilles tarifaires pour le projet 1, puis les dossiers de billets entraîner quelque chose comme:

ticketNumber | ticketDate | projectId | effectiveDate | scheduleId 
------------- | ------------ | ----------- | -------------- | ---------- 
1234   | 2016-06-18 | 25   | 2016-06-01  | 1 
1234   | 2016-06-18 | 25   | 2016-06-15  | 2 
1234   | 2016-06-18 | 25   | 2016-06-31  | 3 

Sélection du effectiveDate dans mes résultats est simple avec l'exemple:

SELECT * 
    , (SELECT TOP 1 t1.effectiveFrom 
     FROM   dbo.labourRateSchedule t1 
     WHERE  t1.effectiveFrom <= t2.[date] and t1.projectId = t2.projectId 
     ORDER BY  t1.effectiveFrom desc) as effectiveDate 

    FROM dbo.timeTicket t2 
    ORDER BY t.date 

Cependant, je dois être capable de joindre l'ID de dbo.labourRateSchedule sur la troisième table pour obtenir les taux réels qui s'appliquent. L'ajout du t1.ID à l'instruction SELECT ne le rend pas accessible à JOIN dans une autre table liée.

J'ai essayé de JOIN l'instruction SELECT dans l'instruction FROM mais les résultats résultent uniquement de la dernière valeur effectiveDate au lieu de celle qui est la plus proche de la ticketDate applicable.

J'apprécierais énormément n'importe quelle aide sur ceci!

+1

Pour effacer les choses un peu s'il vous plaît fournir noms de tables au lieu de "premier, deuxième" afin que la requête puisse être comparée aux structures. – Serg

Répondre

1

Vous pouvez déplacer votre sous-requête à la clause FROM en utilisant CROSS APPLY:

SELECT * 
FROM dbo.timeTicket tt 
CROSS APPLY 
(
    SELECT TOP(1) * 
    FROM dbo.labourRateSchedule lrs 
    WHERE lrs.projectId = tt.projectId 
    AND lrs.effectiveFrom <= tt.date 
    ORDER BY lrs.effectiveFrom desc 
) best_lrs 
JOIN dbo.schedule s on s.schedule_id = best_lrs.schedule_id 
ORDER BY tt.date 
+0

Cela a fonctionné magnifiquement. Je vous remercie. – user2170742

0

Pouvez-vous essayer quelque chose comme ceci (vous devriez changer quelque chose, puisque vous n'avez pas posté toutes les informations).

SELECT A.*, C.* 
    FROM timeTicket A 
    INNER JOIN (SELECT * , ROW_NUMBER() OVER (PARTITION BY projectId ORDER BY effectiveFrom DESC) AS RN 
       FROM labourRateSchedule) B ON A.projectId=B.projectId AND B.RN=1 
    INNER JOIN YOUR3TABLE C ON B.SCHEDULEID=C.SCHEDULEID 
0

Vous pouvez le faire par CTE et la fonction Rank -

create table timeTicket (ticketId int, 
ticketNumber int , 
ticketDate smalldatetime , 
projectId int) 
go 

create table labourRateSchedule 
(scheduleId int, 
projectId int, 
effectiveDate smalldatetime) 
go 

create table ApplicableRates 
(scheduleId int, 
straightTime smalldatetime , 
overTime smalldatetime) 
go 

insert into timeTicket 
select 1 , 1234 ,'2016-06-18' ,25 
go 

insert into labourRateSchedule 
select 1 , 25 ,'2016-06-01' 
union all select 2 , 25 ,'2016-06-15' 
union all select 3 , 25 ,'2016-06-30' 
go 

insert into ApplicableRates  
select 1 , '2016-06-07' ,'2016-06-07' 
union all select 2 , '2016-06-17'  ,'2016-06-17' 
union all select 3 , '2016-06-22'  ,'2016-06-25'   
go 

    with cte 
    as (
    select t1.ticketNumber ,t1.ticketDate ,t1.projectId  ,t2.effectiveDate ,t3.scheduleId ,t3.straightTime  
    ,t3.overTime , rank() over ( partition by t1.ticketNumber order by abs  (DATEDIFF(day,t1.ticketDate, t2.effectiveDate))) DyaDiff 
    from timeTicket t1 join labourRateSchedule t2 
    on t1.projectId = t2.projectId 
    join ApplicableRates t3 
    on t2.scheduleId = t3.scheduleId) 
    select * from cte where DyaDiff = 1