2012-09-17 19 views
18

Tôi có 3 bảng:Hai SQL LEFT NỐI sản xuất kết quả không chính xác

users(id, account_balance) 
grocery(user_id, date, amount_paid) 
fishmarket(user_id, date, amount_paid) 

Cả fishmarketgrocery bảng có thể có nhiều lần xuất hiện cho user_id cùng với các ngày khác nhau và các khoản thanh toán hoặc không có gì ở tất cả cho bất kỳ người dùng nào đó . Khi tôi cố gắng truy vấn sau đây:

SELECT 
    t1."id" AS "User ID", 
    t1.account_balance AS "Account Balance", 
    count(t2.user_id) AS "# of grocery visits", 
    count(t3.user_id) AS "# of fishmarket visits" 
FROM users t1 
LEFT OUTER JOIN grocery t2 ON (t2.user_id=t1."id") 
LEFT OUTER JOIN fishmarket t3 ON (t3.user_id=t1."id") 
GROUP BY t1.account_balance,t1.id 
ORDER BY t1.id 

Nó tạo ra một kết quả không chính xác: "1", "12", "12".
Nhưng khi tôi cố gắng LEFT JOIN chỉ một bảng, nó tạo ra kết quả chính xác cho các chuyến thăm grocery hoặc fishmarket, là "1", "3", "4".

Tôi đang làm gì sai ở đây?
Tôi đang sử dụng PostgreSQL 9.1.

Trả lời

37

Kết nối được xử lý từ trái sang phải (trừ khi dấu ngoặc đơn ra lệnh khác). Nếu bạn LEFT JOIN (hoặc chỉ JOIN, hiệu ứng tương tự) ba cửa hàng tạp hóa cho một người dùng bạn nhận được 3 hàng (1 x 3). Nếu sau đó bạn tham gia 4 điểm đánh cá cho cùng một người dùng, bạn nhận được 12 (3 x 4) hàng, nhân số số trước đó trong kết quả, chứ không phải thêm vào nó, như bạn có thể đã hy vọng.
Qua đó nhân số lượt truy cập cho cửa hàng tạp hóa và điểm cá giống nhau.

Nó sẽ làm việc như thế này:

SELECT u.id 
    , u.account_balance 
    , g.grocery_visits 
    , f.fishmarket_visits 
FROM users u 
LEFT JOIN (
    SELECT user_id, count(*) AS grocery_visits 
    FROM grocery 
    GROUP BY user_id 
    ) g ON g.user_id = u.id 
LEFT JOIN (
    SELECT user_id, count(*) AS fishmarket_visits 
    FROM fishmarket 
    GROUP BY user_id 
    ) f ON f.user_id = u.id 
ORDER BY u.id; 

Để tra cứu giá trị tổng hợp cho một hoặc vài người dùng, truy vấn con tương quanlike @Vince provided là tốt. Đối với toàn bộ bảng hoặc các bộ phận chính của nó, nó là (nhiều) hiệu quả hơn để tổng hợp các bảng n và tham gia kết quả sau khi. Bằng cách này, chúng tôi cũng không cần một khác GROUP BY trong truy vấn bên ngoài.

+2

Chúc mừng thực sự trả lời câu hỏi không chỉ đưa ra một giải pháp. – xception

+0

Mã làm việc trong [link] này (http://rextester.com/ZFFE32806). – HeyJude

+0

@ErwinBrandstetter Tôi đã học được rất nhiều về Postgres từ các bài viết của bạn. Bạn đã bao giờ xem xét việc viết một cuốn sách về chủ đề này chưa? –

2

Đó là vì khi bảng người dùng tham gia vào bảng tạp hóa, có 3 hồ sơ phù hợp. Sau đó, mỗi trong số ba hồ sơ này phù hợp với 4 hồ sơ trong chợ cá, sản xuất 12 hồ sơ. Bạn cần truy vấn phụ để có được những gì bạn đang tìm kiếm.

7

Đối với truy vấn ban đầu của bạn, nếu bạn loại bỏ nhóm bằng cách xem kết quả được nhóm trước, bạn sẽ thấy lý do số lần nhận được đã được tạo.

Có lẽ các truy vấn sau đây sử dụng truy vấn con sẽ đạt được kết quả dự định của bạn:

SELECT 
t1."id" AS "User ID", 
t1.account_balance AS "Account Balance", 
(SELECT count(*) FROM grocery  t2 ON (t2.user_id=t1."id")) AS "# of grocery visits", 
(SELECT count(*) FROM fishmarket t3 ON (t3.user_id=t1."id")) AS "# of fishmarket visits" 
FROM users t1 
ORDER BY t1.id 
Các vấn đề liên quan