2012-03-06 21 views
13

Fondamentalmente ho bisogno di un join esterno sinistro su 2 tabelle (CarePlan e Referral) problema è necessario il più recente Referral Se esiste, è ok se non lo faSQL Server: LEFT OUTER JOIN con TOP 1 per selezionare al massimo una riga

ho queste 2 domande 1. unisce al CarePlan/tavoli di rinvio - crea careplans duplicati se ci sono più riferimenti per un Careplan, o non ha informazioni di riferimento a tutti (join esterno sinistro) 2. selezionare la parte superiore 1 Referral in base alla data, dato un CarePlanId

mi piacerebbe combinare queste 2 così ho afferrare tutte le careplans ed i suoi rinvii, se esiste, se lo fa - prendere solo la più recente rinvio

select * from CarePlan c //query 1 
left outer join Referral r on 
r.CarePlanId = c.CarePlanId 


select top 1 * from Referral r //query 2 
where r.CarePlanId = '1' 
order by ReferralDate desc 

EDIT :

La prima query mi dà qualcosa di simile:

CarePlanID ReferralId  ReferralDate 
---------- ----------  ------------ 
1    1    05/15/12 
2    NULL   NULL 
1    2    05/10/12 //Old date, dont want this careplan 

La seconda query mi darà il rinvio con la data più recente

ReferralId ReferralDate 
---------- ------------ 
1    05/15/12 

I dati di riferimento, possono avere 0 o più rinvii appartenenti ad un Careplan

ReferralID CarePlanId Date 
---------- ---------- ---- 
1   1    05/15/12 
2   1    05/10/12 

in definitiva voglio una query che mi dà careplans con i riferimenti che hanno la data più recente, o null per i rinvii, se si pretende molto hanno si

come questo:

CarePlanId ReferralId ReferralDate 
---------- ---------- ------------ 
1   1    05/15/12 
2   NULL   NULL 

Grazie - Spero che questo ha un senso

+0

avere problemi a leggere quello che vuoi ma penso che quello che ti serve è cercare come fare una tabella cte o derivata. – HLGEM

+0

Puoi mostrare dati di esempio e risultati desiderati? Come @HLGEM non è chiaro da dove stai iniziando e dove vuoi finire. –

+0

È necessario applicare una croce. – usr

risposta

38
select * 
from CarePlan c 
outer apply (
    select top 1 * --top N rows 
    from Referral r 
    where r.CarePlanId = c.CarePlanId --join condition 
    order by /*fill this in!*/ 
) x 

Essere consapevoli che questo costringe un loop join a causa di debolezze Optimizer fino al 2014. versione

1

Solo una supposizione. Non sono sicuro che EF avrà problemi con la sintassi CTE - puoi forzare EF a chiamare una stored procedure in modo da non essere ammanettato dal sottoinsieme di funzionalità supportate da EF?

;WITH r AS 
(
    SELECT CarePlanId, MAX(ReferralDate) 
    FROM dbo.Referrals GROUP BY CarePlanId 
) 
SELECT * FROM dbo.CarePlan AS c 
LEFT OUTER JOIN r 
    ON r.CarePlanId = c.CarePlanId; 
+0

scusa - credo che sia più una domanda SQL generale, Entity Framework non dovrebbe importare qui - almeno spero. Spero anche che i programmi di assistenza resi siano distinti (viene utilizzato solo uno con il riferimento più recente) – Jerrold

+0

Solo tu puoi dirci quest'ultimo - hai cercato di eseguire la query? Restituisce i risultati che ti aspetti? Se ci mostrate dati di esempio e cosa vi aspettate per l'output, è molto più facile per noi provare le nostre risposte prima di lanciarle contro il muro. Inoltre fa risparmiare tempo a tutti. –

6

So che questa domanda è più vecchio, ma c'è un altro approccio che sento è sotto -utilizzato:

È possibile unire le tabelle a se stessi e utilizzare un operatore per trovare il record "più recente".

risposta

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate 
FROM CarePlan CP 
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId 
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate 
WHERE R_NEWER.ReferralId IS NULL 

risultati:

CP.CarePlanId R.ReferralId R.ReferralDate 
----------  ----------  ------------ 
1    1    05/15/12 
2    NULL   NULL 

Spiegazione

Rompiamo questo giù. In pratica, stai dicendo che, per ogni referral, (esterno sinistro) si uniscono ad ogni altro referral record che è associato allo stesso CarePlanId ma SOLO dove c'è un ReferralDate più recente.

Ecco la query senza la clausola in cui (insieme ad alcune informazioni Inoltre dalla tabella R_NEWER):

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate, R_NEWER.ReferralId, R.NEWER.ReferralDate 
FROM CarePlan CP 
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId 
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate 

Qui è il risultato di tale query:

CP.CarePlanId R.ReferralId R.ReferralDate R_NEWER.ReferralId R_NEWER.ReferralDate 
----------  ----------  ------------ ------------  ------------  
1    1    05/15/12  NULL    NULL 
2    NULL   NULL   NULL    NULL 
1    2    05/10/12  1     05/15/12 

Come si può vedere , solo il referral Id 2 (3 ° record sopra) ha trovato un record "più recente" a cui partecipare nella tabella dei referral (ad esempio Id di riferimento 1). L'ID referral 1 (primo record sopra) NON ha trovato un riferimento "più recente" (per lo stesso CarePlanId).

Così, con questo in mente, ora dobbiamo solo aggiungere la clausola dove posteriore:

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate, R_NEWER.ReferralId, R.NEWER.ReferralDate 
FROM CarePlan CP 
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId 
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate 
WHERE R_NEWER.ReferralId IS NULL 

e otteniamo:

CP.CarePlanId R.ReferralId R.ReferralDate R_NEWER.ReferralId R_NEWER.ReferralDate 
----------  ----------  ------------ ------------  ------------  
1    1    05/15/12  NULL    NULL 
2    NULL   NULL   NULL    NULL 

A questo punto, è sufficiente rimuovere le colonne R_NEWER dal SELECT come non sono più necessari e tu hai la tua risposta.

È importante ricordare che il "dove" si applica DOPO che i join si sono verificati, ma l'istruzione ON si verifica al momento del join. Per rendere questo più comprensibile per me, cerco sempre di scrivere SELECT e JOIN e restituire colonne da ogni tabella che sto partecipando e quindi aggiungere le mie clausole WHERE una volta che ho una chiara immagine di ciò che viene restituito.

Caveat Questo approccio funziona alla grande nella maggior parte dei casi, ma è possibile avere righe duplicate se si ha 2 rinvii (per la stessa CarePlanId) con la data del 05/15/12 e che la data era il " piu recente." Per ovviare a ciò, è possibile estendere il/i join/i al limite in base al ReferralId "più alto" se si verifica tale scenario.