Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

MySQL:SUM () với JOIN trả về giá trị không chính xác

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
;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để đọc hình ảnh từ cơ sở dữ liệu MySQL bằng PHP?

  2. Bảng gốc 'performance_schema'. '???' có cấu trúc sai

  3. Làm cách nào để triển khai một tìm kiếm trang web đơn giản với php và mySQL?

  4. Sqoop Nhập - hàm mật khẩu-tệp không hoạt động bình thường trong sqoop 1.4.4

  5. Làm thế nào để tìm các chỉ mục bị thiếu trong MySQL?