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

MySql:Multiple Left Join đưa ra kết quả sai

Bạn cần làm phẳng kết quả truy vấn của bạn, để có được số lượng phù hợp.

Bạn cho biết bạn có mối quan hệ một-nhiều từ bảng tệp của mình sang (các) bảng khác

Nếu SQL chỉ có một từ khóa LOOKUP thay vì nhồi nhét mọi thứ trong JOIN từ khóa, sẽ dễ dàng suy ra nếu mối quan hệ giữa bảng A và bảng B là một-một, bằng cách sử dụng JOIN sẽ tự động bao hàm một-nhiều. Tôi lạc đề. Dù sao thì, lẽ ra tôi phải suy ra rằng các tệp của bạn là một-nhiều đối với dm_data; và các tệp chống lại kc_data cũng là một-nhiều. LEFT JOIN là một gợi ý khác rằng mối quan hệ giữa bảng đầu tiên và bảng thứ hai là một-nhiều; Tuy nhiên, điều này không phải là chắc chắn, một số người viết mã chỉ viết mọi thứ bằng LEFT JOIN . Không có gì sai với THAM GIA TRÁI trong truy vấn của bạn, nhưng nếu có nhiều bảng từ một đến nhiều trong truy vấn của bạn, điều đó chắc chắn sẽ không thành công, truy vấn của bạn sẽ tạo ra các hàng lặp lại so với các hàng khác.

from
    files
        left join
    dm_data ON dm_data.id = files.id
        left join
    kc_data ON kc_data.id = files.id

Vì vậy, với kiến ​​thức này, bạn chỉ ra rằng các tệp là một-nhiều đối với dm_data và một-nhiều cũng chống lại kc_data. Chúng tôi có thể kết luận rằng có điều gì đó sai khi liên kết các liên kết đó và nhóm chúng lại trên một truy vấn nguyên khối.

Ví dụ nếu bạn có ba bảng, đó là ứng dụng (tệp), ios_app (dm_data), android_app (kc_data) và đây là dữ liệu ví dụ cho ios:

test=# select * from ios_app order by app_code, date_released;
 ios_app_id | app_code | date_released | price  
------------+----------+---------------+--------
          1 | AB       | 2010-01-01    | 1.0000
          3 | AB       | 2010-01-03    | 3.0000
          4 | AB       | 2010-01-04    | 4.0000
          2 | TR       | 2010-01-02    | 2.0000
          5 | TR       | 2010-01-05    | 5.0000
(5 rows)

Và đây là dữ liệu cho android của bạn:

test=# select * from android_app order by app_code, date_released;
.android_app_id | app_code | date_released |  price  
----------------+----------+---------------+---------
              1 | AB       | 2010-01-06    |  6.0000
              2 | AB       | 2010-01-07    |  7.0000
              7 | MK       | 2010-01-07    |  7.0000
              3 | TR       | 2010-01-08    |  8.0000
              4 | TR       | 2010-01-09    |  9.0000
              5 | TR       | 2010-01-10    | 10.0000
              6 | TR       | 2010-01-11    | 11.0000
(7 rows)    

Nếu bạn chỉ sử dụng truy vấn này:

select x.app_code, 
    count(i.date_released) as ios_release_count, 
    count(a.date_released) as android_release_count
from app x
left join ios_app i on i.app_code = x.app_code
left join android_app a on a.app_code = x.app_code
group by x.app_code
order by x.app_code

Thay vào đó, đầu ra sẽ bị sai:

 app_code | ios_release_count | android_release_count 
----------+-------------------+-----------------------
 AB       |                 6 |                     6
 MK       |                 0 |                     1
 PM       |                 0 |                     0
 TR       |                 8 |                     8
(4 rows)

Bạn có thể coi các liên kết được xâu chuỗi như là một sản phẩm của cartesian, vì vậy nếu bạn có 3 hàng trên bảng đầu tiên và có 2 hàng trên bảng thứ hai, thì kết quả đầu ra sẽ là 6

Đây là hình ảnh trực quan, hãy thấy rằng có 2 android AB lặp lại cho mỗi ios AB. Có 3 ios AB, vậy số lượng sẽ là bao nhiêu khi bạn thực hiện COUNT (ios_app.date_released)? Điều đó sẽ trở thành 6; tương tự với COUNT(android_app.date_released) , đây cũng sẽ là 6. Tương tự như vậy, có 4 TR android lặp lại cho mỗi TR của ios, có 2 TR trong ios, vì vậy sẽ cho chúng ta số lượng là 8.

.app_code | ios_release_date | android_release_date 
----------+------------------+----------------------
 AB       | 2010-01-01       | 2010-01-06
 AB       | 2010-01-01       | 2010-01-07
 AB       | 2010-01-03       | 2010-01-06
 AB       | 2010-01-03       | 2010-01-07
 AB       | 2010-01-04       | 2010-01-06
 AB       | 2010-01-04       | 2010-01-07
 MK       |                  | 2010-01-07
 PM       |                  | 
 TR       | 2010-01-02       | 2010-01-08
 TR       | 2010-01-02       | 2010-01-09
 TR       | 2010-01-02       | 2010-01-10
 TR       | 2010-01-02       | 2010-01-11
 TR       | 2010-01-05       | 2010-01-08
 TR       | 2010-01-05       | 2010-01-09
 TR       | 2010-01-05       | 2010-01-10
 TR       | 2010-01-05       | 2010-01-11
(16 rows)

Vì vậy, những gì bạn nên làm là san bằng từng kết quả trước khi nối chúng với các bảng và truy vấn khác.

Nếu cơ sở dữ liệu của bạn có khả năng CTE, hãy sử dụng. Nó rất gọn gàng và rất tự ghi lại:

with ios_app_release_count_list as
(
 select app_code, count(date_released) as ios_release_count
 from ios_app
 group by app_code
)
,android_release_count_list as
(
 select app_code, count(date_released) as android_release_count 
 from android_app 
 group by app_code  
)
select
 x.app_code, 
 coalesce(i.ios_release_count,0) as ios_release_count, 
 coalesce(a.android_release_count,0) as android_release_count
from app x
left join ios_app_release_count_list i on i.app_code = x.app_code
left join android_release_count_list a on a.app_code = x.app_code
order by x.app_code;

Trong khi nếu cơ sở dữ liệu của bạn chưa có khả năng CTE, chẳng hạn như MySQL, bạn nên thực hiện việc này thay thế:

select x.app_code, 
 coalesce(i.ios_release_count,0) as ios_release_count, 
 coalesce(a.android_release_count,0) as android_release_count
from app x
left join
(
 select app_code, count(date_released) as ios_release_count
 from ios_app
 group by app_code
) i on i.app_code = x.app_code
left join
(
 select app_code, count(date_released) as android_release_count 
 from android_app 
 group by app_code   
) a on a.app_code = x.app_code
order by x.app_code

Truy vấn đó và truy vấn kiểu CTE sẽ hiển thị đầu ra chính xác:

 app_code | ios_release_count | android_release_count 
----------+-------------------+-----------------------
 AB       |                 3 |                     2
 MK       |                 0 |                     1
 PM       |                 0 |                     0
 TR       |                 2 |                     4
(4 rows)

Kiểm tra trực tiếp

Truy vấn không chính xác: http://www.sqlfiddle.com/#!2/9774a/ 2

Truy vấn đúng: http://www.sqlfiddle.com/#!2/9774a/ 1



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Trả lại truy vấn trong một định dạng khôn ngoan hàng thay vì cột

  2. Tôi có nên sử dụng backticks hay không khi thoát từ khóa trong MySQL?

  3. Tự động tải dữ liệu trên cuộn div bằng php, mysql, jquery và ajax

  4. Tạo cột tổng tích lũy trong MySQL

  5. Làm cách nào để xử lý các dấu ngoặc kép bên trong một truy vấn SQL trong PHP?