2009-05-27 15 views
99

Ho un LIVELLO ESTERNO SINISTRO molto semplice per restituire tutti i risultati dalla tabella sinistra e alcune informazioni aggiuntive da una tabella molto più grande. La tabella di sinistra contiene 4935 record ancora quando I LEFT OUTER UNISCONO a una tabella aggiuntiva il numero di record è significativamente più grande.Come può un LEFT OUTER JOIN restituire più record di quelli esistenti nella tabella sinistra?

Per quanto ne so, è un vangelo assoluto che un LEFT OUTER JOIN restituirà tutti i record dalla tabella sinistra con i record corrispondenti dalla tabella di destra e valori null per tutte le righe che non possono essere abbinate, in quanto tale è il mio capendo che dovrebbe essere impossibile restituire più file di quante ne esistano nella tabella sinistra, ma sta succedendo lo stesso!

SQL Query segue:

SELECT  SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID 
FROM   SUSP.Susp_Visits LEFT OUTER JOIN 
         DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum 

Forse ho commesso un errore nella sintassi o la mia comprensione di LEFT OUTER JOIN è incompleta, qualunque sia la ragione per cui sto impazzendo qui, si spera che qualcuno può spiegare come questo potrebbe essere in corso?

Postscript

Grazie per le risposte Grea, la mia comprensione di SINISTRA outer join è ora molto meglio, qualcuno però potrebbe suggerire un modo in cui questa domanda potrebbe essere modificata in modo che io ho soltanto il maggior numero di record restituiti come esistono nel tavolo sinistro?

Questa query è puramente per generare un report e le corrispondenze duplicate semplicemente confondono le cose.

/Postscript

+3

Per "ottenere il numero di record restituito esistente nella tabella sinistra", è necessario specificare quale riga dal lato destro a scegli se ci sono più corrispondenze. –

+0

come lo si specifica? Mi piacerebbe che la prima partita fosse restituita. –

+0

devi definire cosa si intende per prima corrispondenza. Vuoi la primissima registrazione, quella con l'id più alto o cosa? – HLGEM

risposta

121

esterno sinistro ENTRA restituirà tutti i record dalla tabella a sinistra unito con la tabella di destra, ove possibile.

Se vi sono corrispondenze però, sarà ancora restituire tutte le righe che corrispondono, pertanto, una riga nella LEFT che soddisfa due file destri tornerà come due file, come inner join.

MODIFICA: In seguito alla modifica, ho appena esaminato la query e sembra che si stiano restituendo solo i dati dalla tabella SINISTRA. Pertanto, se si desidera solo i dati dalla tabella SINISTRA e si desidera solo una riga restituita per ogni riga nella tabella SINISTRA, non è necessario eseguire un JOIN e si può semplicemente eseguire una SELEZIONE direttamente dalla tabella SINISTRA.

6

Potrebbe essere una relazione uno a molti tra i tavoli sinistro e destro?

1

Sembra che ci siano più righe nella tabella DATA.Dim_Member per riga SUSP.Susp_Visits.

21

Non è impossibile. Il numero di record nella tabella sinistra è il numero minimo di record che restituirà. Se la tabella di destra ha due record che corrispondono a un record nella tabella di sinistra, restituirà due record.

7

Ogni record dalla tabella di sinistra sarà restituito tante volte quanti sono i corrispondenti risultati sulla tabella di destra - almeno 1, ma potrebbe facilmente essere superiore a 1.

1

se più (x) righe in Dim_Member sono associati a una singola riga in Susp_Visits, ci saranno x righe nel set di resul.

7

LEFT OUTER JOIN come INNER JOIN (join normale) restituirà tanti risultati per ogni riga nella tabella sinistra quante più corrispondenze trova nella tabella corretta. Quindi puoi avere molti risultati - fino a N x M, dove N è il numero di righe nella tabella sinistra e M è il numero di righe nella tabella destra.

E 'il numero minimo di risultati è sempre garantita in LEFT OUTER JOIN essere almeno N.

+0

Ho iniziato a pensare quando il numero di righe è uguale N x M e l'unica situazione reale che mi viene in mente è quando N o M è uguale a 1. Sei d'accordo? – MrKiller21

+1

No, non lo so. Non dovresti pensare a condizioni di join come join di uguaglianza chiave solo. Può essere una condizione arbitraria, ad es. intervalli di date, disuguaglianze, ecc. Due casi estremi: (a) Le righe N non hanno una singola corrispondenza tra le righe M, quindi i risultati dell'unione esterna sinistra in N righe corrispondono a NULL. (b) ognuna delle N righe corrisponde a tutte le righe M, quindi il risultato è N x M set di righe. – topchef

+0

Hai ragione, stavo pensando ai join solo in termini di uguaglianza chiave. Mi piace il tuo esempio da "case b". Credo che "tutte le righe N corrispondano a tutte le righe M" sia una ricetta generale per quando vengono restituite righe N x M, il che è piuttosto impossibile da visualizzare quando si pensa solo all'eguaglianza delle chiavi. – MrKiller21

78
Table1    Table2 
_______    _________ 
1      2 
2      2 
3      5 
4      6 

SELECT Table1.Id, Table2.Id FROM Table1 LEFT OUTER JOIN Table2 ON Table1.Id=Table2.Id 

Risultati:

1,null 
2,2 
2,2 
3,null 
4,null 
4

Se avete bisogno di un qualsiasi una riga dal lato destro

SELECT SuspReason, SiteID FROM(
    SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER() 
    OVER(PARTITION BY SUSP.Susp_Visits.SiteID) AS rn 
    FROM SUSP.Susp_Visits 
    LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum 
) AS t 
WHERE rn=1 

o semplicemente

SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID 
FROM SUSP.Susp_Visits WHERE EXISTS(
    SELECT DATA.Dim_Member WHERE SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum 
) 
+0

Poiché non hai fornito DDL e DML, non ho eseguito il test. Comunque penso che ESISTE sia quello che vuoi. Prova questo: SELEZIONA SuspReason, SiteID FROM (SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER() OVER (partizione CON ORDINANZA SUSP.Susp_Visits.SiteID BY SUSP.Susp_Visits.SiteID) AS RN DA SUSP. Susp_Visits LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) AS t WHERE rn = 1 –

10

In risposta al tuo poscritto, ciò dipende da ciò che desideri.

Si stanno ottenendo (possibili) più righe per ogni riga nella tabella di sinistra perché ci sono più corrispondenze per la condizione di join. Se vuoi che i tuoi risultati totali abbiano lo stesso numero di righe che ci sono nella parte sinistra della query, devi assicurarti che le tue condizioni di join causino una corrispondenza 1 a 1.

In alternativa, in base a ciò che effettivamente si desidera è possibile utilizzare le funzioni di aggregazione (se ad esempio si desidera semplicemente una stringa dalla parte destra è possibile generare una colonna che è una stringa delimitata da virgole dei risultati del lato destro per quella riga sinistra .

Se sei solo alla ricerca a 1 o 2 colonne della outer join si potrebbe considerare l'utilizzo di una subquery scalare in quanto vi sarà garantito 1 risultato.

+3

Questa è una buona risposta poiché ha offerto suggerimenti su come restituire solo righe dalla tabella sinistra. – karns

6

Prestare attenzione se si dispone di una clausola in cui sul "diritto lato 'tabella di una query contenente un join esterno sinistro ... Nel caso in cui non si abbia record sul lato destro che soddisfa la clausola where, quindi il rec corrispondente ord della tabella 'lato sinistro' non apparirà nel risultato della query ....

+0

È quindi necessario aggiungere la condizione alla clausola ON del corrispondente JOINT OUTER JOIN. – Mik

Problemi correlati