2014-09-09 17 views
5

SQL Fiddle HereLEFT OUTER JOIN Con Condizione In Terza tavola

scrittori SQL brillanti,

Sto cercando di ottenere tutte le date in un certo intervallo (memorizzati come record nel T1), e la somma dei valori di record in una tabella correlata (T2). Tuttavia, alcuni dei record in T2 verranno filtrati in base al valore di un campo in una terza tabella (T3).

tabelle Assumendo come questo:

TABLE T1 
| MonthYearKey | 
|==============| 
| 201401  | 
| 201402  | 
| 201403  | 
| 201404  | 
| 201405  | 
| 201406  | 

TABLE T2 
| MonthYearKey | NextKey | MyValue | 
|==============+=========+=========| 
| 201402  | 6  | 10  | 
| 201403  | 6  | 10  | 
| 201404  | 6  | 10  | 
| 201402  | 8  | 10  | 
| 201403  | 8  | 10  | 
| 201404  | 8  | 10  | 
| 201401  | 10  | 10  | 
| 201402  | 10  | 10  | 
| 201406  | 10  | 10  | 

TABLE T3 
| NextKey | IsValid | 
|=========+=========| 
| 6  | 1  | 
| 8  | 1  | 
| 10  | 0  | 

Lo SQL sto facendo funzionare è:

SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues 
FROM T1 
    LEFT OUTER JOIN T2 ON T1.MonthYearKey = T2.MonthYearKey 
    LEFT OUTER JOIN T3 ON T2.NextKey = T3.NextKey 
WHERE ISNULL(T3.IsValid, 1) = 1 
GROUP BY T1.MonthYearKey 

L'uscita mi aspettavo è:

| MonthYearKey | SumOfValues | 
|==============+=============| 
| 201401  | 0   | 
| 201402  | 20   | 
| 201403  | 20   | 
| 201404  | 20   | 
| 201405  | 0   | 
| 201406  | 0   | 

Tuttavia, come si può vedere in SQL Fiddle, i mesi 201401 e 201406 vengono completamente esclusi dai risultati. Presumo che questo è perché ha selezionato i record con NextKey = 10, che poi è stato filtrato dal IsValid = 0.

DOMANDA: Come posso ottenere tutti i MonthYearKeys, anche quelli che sono attualmente in fase di filtrati nel mio SQL?

risposta

2

Prova questo:

SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues 
FROM T1 
    LEFT OUTER JOIN (
    SELECT T2.MyValue, T2.MonthYearKey 
    FROM T2 
    JOIN T3 ON T2.NextKey = T3.NextKey AND ISNULL(T3.IsValid, 1) = 1 
) T2 ON T1.MonthYearKey = T2.MonthYearKey 
GROUP BY T1.MonthYearKey 

Prova qui: http://www.sqlfiddle.com/#!3/4a333/26

EDIT:

Senza di query nidificate:

SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues 
    FROM T2 
    JOIN T3 ON T2.NextKey = T3.NextKey AND T3.IsValid = 1 
    RIGHT OUTER JOIN T1 ON T1.MonthYearKey = T2.MonthYearKey 
GROUP BY T1.MonthYearKey 

Senza di query nidificate modificando JOIN precedenza:

SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues 
FROM T1 
    LEFT OUTER JOIN (T2 JOIN T3 ON T2.NextKey = T3.NextKey AND T3.IsValid = 1) 
    ON T1.MonthYearKey = T2.MonthYearKey 
GROUP BY T1.MonthYearKey 

SQL Fidle: http://www.sqlfiddle.com/#!3/4a333/45

4

Quando si applica il filtro nella clausola where, si perdono le righe, inclusa la colonna utilizzata per group by.

Al contrario, utilizzare l'aggregazione condizionale:

SELECT T1.MonthYearKey, 
     COALESCE(SUM(case when t3.isvalid is null or t3.isvalid = 1 
         then T2.MyValue 
        end), 0 
       ) as SumOfValues 
FROM T1 LEFT OUTER JOIN 
    T2 
    ON T1.MonthYearKey = T2.MonthYearKey LEFT OUTER JOIN T3 
    ON T2.NextKey = T3.NextKey 
GROUP BY T1.MonthYearKey; 
+0

vedo che è stata utilizzata la funzione di COALESCE per assicurarsi che tutti i mesi hanno un valore pari a zero se non ha risultati Perché hai scelto COALESCE invece di ISNULL (non ho usato COALESCE prima)? COALESCE ha implicazioni sulle prestazioni poiché viene valutata più volte o implicazioni sull'affidabilità poiché i risultati potrebbero cambiare (vedere http://msdn.microsoft.com/en-us/library/ms190349.aspx) – laughsloudly

+2

Preferisco 'coalizione()' perché è la funzione standard ANSI. Tuttavia, 'isnull()' è spesso preferito in SQL Server, perché (a mio parere) SQL Server ha un'implementazione rotta di 'coalesce()'. Quindi, sentiti libero di usare entrambi. –