Hãy thử truy vấn này:
SELECT bl.user_id, SUM( ph.amount ) PAIDOUT
FROM (
SELECT distinct blocks.user_id
FROM blocks
WHERE confirms > 520
) bl
LEFT JOIN payout_history ph
ON bl.user_id = ph.user_id
GROUP BY ph.user_id
;
SQLFiddle -> http://sqlfiddle.com/#!2/7b988/48
--- EDIT --- giải thích cách hoạt động của truy vấn (hay đúng hơn là tại sao truy vấn của bạn không hoạt động) ----
Nhìn vào kết quả mong đợi, có vẻ như truy vấn sẽ tính tổng của amount
cho mỗi user_id
, nhưng chỉ dành cho những user_id
đó , cũng nằm trong các khối blocks
bảng và có blocks.confirms
giá trị lớn hơn 520.
Một phép nối đơn giản (cũng là phép nối ngoài cùng bên trái) không thể hoạt động trong trường hợp này, vì các khối blocks
bảng có thể chứa nhiều bản ghi cho cùng một user_id
, ví dụ:một truy vấn chỉ trả về các hàng cho user_id=110
cho các kết quả sau:
SELECT *
FROM blocks
WHERE confirms > 520
AND user_id = 110;
+ ------- + ------------ + ----------- + ------------- +
| id | user_id | reward | confirms |
+ ------- + ------------ + ----------- + ------------- +
| 0 | 110 | 20.89832115 | 521 |
| 65174 | 110 | 3.80357075 | 698 |
| 65204 | 110 | 4.41933060 | 668 |
| 65218 | 110 | 4.69059801 | 654 |
| 65219 | 110 | 4.70222521 | 653 |
| 65230 | 110 | 4.82805490 | 642 |
| 65265 | 110 | 5.25058079 | 607 |
| 65316 | 110 | 6.17262650 | 556 |
+ ------- + ------------ + ----------- + ------------- +
Phép nối thẳng (và phép nối bên ngoài LEFT / RIGHT) hoạt động theo cách này, lấy từng bản ghi từ bảng được nối đầu tiên và ghép nối bản ghi này (kết hợp nó) với tất cả các hàng từ bảng được nối khác đáp ứng điều kiện nối.
Trong trường hợp của chúng tôi, phép nối bên trái tạo ra tập kết quả dưới đây:
SELECT *
FROM blocks
LEFT JOIN payout_history
ON blocks.user_id = payout_history.user_id
WHERE confirms > 520
AND blocks.user_id = 110;
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
| id | user_id | reward | confirms | id | user_id | amount |
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
| 0 | 110 | 20.89832115 | 521 | 1 | 110 | 20.898319 |
| 65174 | 110 | 3.80357075 | 698 | 1 | 110 | 20.898319 |
| 65204 | 110 | 4.41933060 | 668 | 1 | 110 | 20.898319 |
| 65218 | 110 | 4.69059801 | 654 | 1 | 110 | 20.898319 |
| 65219 | 110 | 4.70222521 | 653 | 1 | 110 | 20.898319 |
| 65230 | 110 | 4.82805490 | 642 | 1 | 110 | 20.898319 |
| 65265 | 110 | 5.25058079 | 607 | 1 | 110 | 20.898319 |
| 65316 | 110 | 6.17262650 | 556 | 1 | 110 | 20.898319 |
+ ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
và bây giờ nếu chúng ta thêm SUM( amount ) .... GROUP BY user_id
, MySql sẽ tính tổng của tất cả amount
giá trị từ tập kết quả ở trên (8 hàng * 20.898 =~ 167.184)
SELECT blocks.user_id, sum( amount)
FROM blocks
LEFT JOIN payout_history
ON blocks.user_id = payout_history.user_id
WHERE confirms > 520
AND blocks.user_id = 110
GROUP BY blocks.user_id;
+ ------------ + ----------------- +
| user_id | sum( amount) |
+ ------------ + ----------------- +
| 110 | 167.186554 |
+ ------------ + ----------------- +
Như bạn thấy trong trường hợp này, phép nối không mang lại cho chúng tôi kết quả mong muốn - chúng tôi cần một thứ có tên a semi join
- dưới đây là các biến thể khác nhau của bán nối, hãy thử:
SELECT bl.user_id, SUM( ph.amount ) PAIDOUT
FROM (
SELECT distinct blocks.user_id
FROM blocks
WHERE confirms > 520
) bl
LEFT JOIN payout_history ph
ON bl.user_id = ph.user_id
GROUP BY ph.user_id
;
SELECT ph.user_id, SUM( ph.amount ) PAIDOUT
FROM payout_history ph
WHERE ph.user_id IN (
SELECT user_id FROM blocks
WHERE confirms > 520
)
GROUP BY ph.user_id
;
SELECT ph.user_id, SUM( ph.amount ) PAIDOUT
FROM payout_history ph
WHERE EXISTS (
SELECT 1 FROM blocks bl
WHERE bl.user_id = ph.user_id
AND bl.confirms > 520
)
GROUP BY ph.user_id
;