2012-05-14 35 views
8

Tải xuống bao gồm số lần tải xuống, id thời gian tải xuống và ID buno. Lỗi bao gồm mã lỗi, id thời gian tải xuống, trạng thái và loại. Tải xuống có thể có nhiều lỗi và có thể được kết hợp trên id thời gian tải xuống.Tham gia bên ngoài bên trái trong Postgres Không trả lại giá trị cho Null

Đưa ra một bộ mã lỗi, kết quả phải chứa từng mã lỗi với số lượng lỗi tương ứng. Nếu không tìm thấy mã lỗi trong quá trình tải xuống, mã lỗi phải được trả về với số lỗi là 0.

Vấn đề dường như yêu cầu OUTER JOIN, nhưng chưa thấy điều này làm việc như mong đợi trên Postgres vì ​​nó dường như không trả về tập hợp có null từ bảng LEFT.

Truy vấn dưới đây, với một số chi tiết rời ra cho ngắn gọn:

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
LEFT OUTER JOIN fs_fault f ON f.downloadtimeid = d.id 
    AND f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
WHERE (d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Ngày hôm sau, tôi đã chỉnh sửa để hiển thị các câu trả lời. Tất cả các câu trả lời đều gần gũi và có các yếu tố hỗ trợ khác nhau. Tuy nhiên, câu trả lời của JayC là gần nhất. Đây là SQL thức, có sự thay đổi duy nhất là mệnh đề WHERE lấy lỗi mã trong tuyên bố:

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON f.downloadtimeid = d.id 
     AND f.statusid IN(2, 4) 
     AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012' 
     AND d.bunoid = 166501 
WHERE f.faultcode IN (1000,1100) 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Cảm ơn, tất cả sự giúp đỡ của bạn! Yêu trang web này!

+1

Bạn đã phân tích dữ liệu của mình chưa? Tôi nghi ngờ nó là vấn đề trong PostgreSQL ... Bạn có thể cung cấp cấu trúc bảng và dữ liệu mẫu trong [SQL Fiddle] (http://sqlfiddle.com/) không? – vyegorov

+1

'download_time d LEFT OUTER JOIN fs_fault f ON f.downloadtimeid = d.id' có' download_time' làm bảng bên trái, không phải 'fs_fault'. Điều kiện kết nối không liên quan gì đến bảng nào là trái hay phải trong phép nối. – JayC

Trả lời

20

Tôi đang đưa ra câu trả lời vì tôi có những nghi ngờ đáng kể về các câu trả lời khác. Bạn phải cẩn thận về các yêu cầu bộ lọc. Hãy nhớ, mệnh đề where chạy sau khi bạn tham gia. Vì vậy, nếu có bất kỳ yêu cầu bộ lọc trong mệnh đề where tham chiếu đến bảng không nối ngoài, bạn có (trong nhiều trường hợp) đã vô hiệu hóa phép nối ngoài của bạn. Vì vậy, lấy sql của bạn, Dường như giải pháp đơn giản nhất là sử dụng phép nối thích hợp hoặc di chuyển tên bảng một cách thích hợp, và sau đó di chuyển các điều kiện lọc ra khỏi mệnh đề where và vào mệnh đề join.

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON 
    f.downloadtimeid = d.id 
    AND f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
    AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Một cách khác mà tôi tin rằng cần phải tương đương là

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON 
    f.downloadtimeid = d.id 
    AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
WHERE 
    f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Vì nó không đúng vấn đề mà các yêu cầu bộ lọc trên fs_fault đang có. (và công cụ SQL của bạn sẽ thay đổi mọi thứ).

Chỉnh sửa: Dưới đây là SQLFiddle trình bày lọc trên mệnh đề kết hợp so với mệnh đề where.

+1

Bạn nói đúng về mệnh đề 'WHERE' so với điều kiện' JOIN'. Tôi đã cố định câu trả lời của mình trong vấn đề đó. Tôi không nghĩ rằng bạn đã giải quyết câu hỏi của mình về làm thế nào để có được các mã lỗi mong muốn để hiển thị * ngay cả khi không có xảy ra *, mặc dù. – kgrittn

+0

Cảm ơn tất cả các bạn: Tôi đã ghi nhận một phiếu bầu cho tất cả những người trả lời, vì tôi đã học được điều gì đó từ mỗi người. Tuy nhiên, JayC, bạn thân thiết nhất. Thay đổi duy nhất là di chuyển 'f.faultcode IN (1000,1100)' sang mệnh đề where. Khi làm điều đó, các mã lỗi chính xác được hiển thị. Cảm ơn, JayC! – MAbraham1

+0

Tôi không thể làm cho SQLFiddle hoạt động. Tôi đang sử dụng IE 7.0.5730.13CO, vì tôi đang làm việc. Tôi sẽ phải thử ở nhà, nơi tôi thường chạy Chrome. – MAbraham1

2

Điều này sẽ yêu cầu RIGHT OUTER JOIN. Tham gia bên ngoài bên phải bao gồm tất cả các giá trị từ bảng bên phải, với NULL s nơi không có mục nhập trong bảng bên trái (tôi không chắc chắn nếu điều này sẽ hoạt động với GROUP BY, mặc dù ...) nếufs_fault là một bảng tất cả các mã lỗi.

Trong trường hợp của bạn, fs_fault dường như chứa mọi lỗi để tải xuống. Đây có phải là trường hợp của hành vi không mong muốn không?

1

Kết nối bên ngoài bên trái chọn mọi thứ trong bảng đầu tiên cộng với các hàng phù hợp trong bảng thứ hai. Bảng đầu tiên dường như bao gồm các lần tải xuống. Vì vậy, kết quả của bạn từ "từ" bao gồm tất cả các lần tải xuống.

Nhưng, nó không nhất thiết phải chứa tất cả các mã lỗi của bạn. Điều đang xảy ra là bạn không có lỗi cho một hoặc nhiều mã đáp ứng tiêu chí.

Bạn cần một bảng có chứa tất cả các mã lỗi, để làm việc này. Ở đây tôi chỉ cần tạo một danh sách các mã lỗi như bảng đầu tiên. Tôi nghĩ truy vấn sau thực hiện điều này:

SELECT thefaults.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM (select 1000 as faultcode union all select 1100 
    ) thefaults join 
     fs_fault f 
     on f.faultcode = thefaults.faultcode and 
     f.statusid in (2, 4) left outer join 
     download_time d 
     ON f.downloadtimeid = d.id 
WHERE (d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') AND 
     d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Tôi thừa nhận: Tôi đang sử dụng cú pháp SQL Server để tạo "các kết nối".

+0

Nếu một mã lỗi không có thời gian tải xuống được liên kết, nó sẽ được lọc theo mệnh đề where. – JayC

+0

Một giả định đây là những gì người hỏi muốn. –

2

Nếu bạn muốn đếm bởi faultcode, điều này có vẻ như là giải pháp đơn giản nhất:

WITH fc(faultcode) AS (VALUES (1000,1100)) 
SELECT fc.faultcode, count(d.downloadtimeid) as faultcount 
    FROM fc 
    LEFT JOIN (fs_fault f ON f.faultcode = fc.faultcode 
         AND f.statusid IN(2, 4) 
    JOIN download_time d ON d.id = f.downloadtimeid 
         AND d.bunoid = 166501 
         AND d.downloadtime::date BETWEEN date '2011-04-11' 
                AND date '2011-05-01') 
    GROUP BY fc.faultcode 
    ORDER BY fc.faultcode 

Lưu ý rằng tôi vẫn tiếp tục điều kiện của bạn, nơi những lỗi lầm không được tính nếu họ không có statusid đúng hay bunoid. Tôi hơi sợ rằng việc lựa chọn ngày tháng có thể đã không làm những gì bạn nghĩ, vì vậy tôi đề nghị một sự thay thế. Thậm chí điều đó có thể không làm những gì bạn muốn nếu bạn đang sử dụng TIMESTAMP WITHOUT TIME ZONE, nhưng đó là một câu chuyện khác. Tôi cũng đã thêm một điều khoản ORDER BY, vì bạn có thể không muốn kết quả theo thứ tự không nhất quán; không có mệnh đề đó, nó có thể có hoặc không nằm trong chuỗi GROUP BY và có thể thay đổi mà không cần cảnh báo.

+0

Nếu một mã lỗi không có thời gian tải xuống được liên kết, nó sẽ được lọc theo mệnh đề where. – JayC

+0

Rất tiếc. Cố định bằng cách thêm dấu ngoặc đơn để buộc thứ tự đánh giá các kết nối. Cảm ơn! – kgrittn

+0

@JayC đã đưa ra một điểm tốt về mệnh đề 'WHERE' so với điều kiện' JOIN' trong câu trả lời của anh ta. Như nó đã được viết, nếu * chỉ * hàng cho một mã lỗi cụ thể đã bị loại trừ bởi các điều kiện, thì faultocde sẽ không xuất hiện. Cố định bằng cách di chuyển các điều kiện. – kgrittn

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