2014-09-09 17 views
5

SQL Fiddle HereLEFT OUTER JOIN Với Điều kiện Trong bảng thứ ba

Writers SQL Brilliant,

tôi đang cố gắng để có được tất cả các ngày trong một phạm vi nhất định (lưu dưới dạng các bản ghi trong T1), và tổng các giá trị các bản ghi trong bảng liên quan (T2). Tuy nhiên, một số bản ghi trong T2 sẽ được lọc ra theo giá trị của một trường trong bảng thứ ba (T3).

bảng Giả sử như thế này:

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  | 

SQL Tôi đang chạy là:

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 

Kết quả mong đợi của tôi là:

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

Tuy nhiên, như bạn có thể nhìn thấy trong SQL Fiddle, các tháng 201401 và 201406 được loại bỏ hoàn toàn khỏi kết quả. Tôi giả định này là bởi vì nó được lựa chọn các hồ sơ với NextKey = 10, sau đó được lọc ra bởi IsValid = 0.

HỎI: Làm thế nào tôi có thể nhận được TẤT CẢ các MonthYearKeys, ngay cả những người hiện đang được lọc ra trong SQL của tôi?

Trả lời

2

Hãy thử điều này:

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 

Hãy thử ở đây: http://www.sqlfiddle.com/#!3/4a333/26

EDIT:

Nếu không có truy vấn lồng nhau:

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 

Nếu không có truy vấn lồng nhau bằng cách thay đổi JOIN ưu tiên:

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

Khi bạn áp dụng bộ lọc trong mệnh đề where, bạn sẽ mất các hàng - bao gồm cột được sử dụng cho group by.

Thay vào đó, sử dụng kết hợp có điều kiện:

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

Tôi thấy rằng bạn sử dụng các chức năng liên hiệp để đảm bảo rằng tất cả các tháng có giá trị bằng không nếu họ không có kết quả. Tại sao bạn chọn COALESCE thay vì ISNULL (trước đây tôi chưa sử dụng COALESCE)? COALESCE có bất kỳ hàm ý hiệu suất nào vì nó được đánh giá nhiều lần hay các hệ lụy đáng tin cậy do kết quả có thể thay đổi (xem http://msdn.microsoft.com/en-us/library/ms190349.aspx) – laughsloudly

+2

Tôi thích 'coalesce()' bởi vì nó là hàm chuẩn ANSI. Tuy nhiên, 'isnull()' thường được ưa thích trong SQL Server, bởi vì (theo ý kiến ​​của tôi) SQL Server có một sự thực thi bị hỏng của 'coalesce()'. Vì vậy, hãy sử dụng một trong hai. –

Các vấn đề liên quan