Mysql
 sql >> Baza danych >  >> RDS >> Mysql

MySql:wielokrotne lewe sprzężenie dające błędne dane wyjściowe

Musisz spłaszczyć wyniki zapytania, aby uzyskać właściwą liczbę.

Powiedziałeś, że masz relację jeden-do-wielu między tabelą plików a innymi tabelami

Jeśli SQL zawiera tylko słowo kluczowe LOOKUP zamiast wpychać wszystko w JOIN słowa kluczowe, powinno być łatwo wywnioskować, czy relacja między tabelą A i tabelą B jest jeden do jednego, używając JOIN automatycznie oznacza jeden do wielu. Dygresję. W każdym razie powinienem był już wywnioskować, że twoje pliki są jeden do wielu w stosunku do dm_data; a także pliki przeciwko kc_data to też jeden do wielu. LEFT JOIN jest kolejną wskazówką, że relacja między pierwszą a drugą tabelą to jeden do wielu; nie jest to jednak ostateczne, niektórzy programiści po prostu piszą wszystko za pomocą LEFT JOIN . Nie ma nic złego w LEFT JOIN w zapytaniu, ale jeśli w zapytaniu jest wiele tabel typu jeden-do-wielu, które z pewnością się nie powiedzie, zapytanie wygeneruje powtarzające się wiersze w stosunku do innych wierszy.

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

Tak więc z tą wiedzą, że wskazujesz, że pliki są jeden do wielu w stosunku do dm_data i jeden do wielu również w stosunku do kc_data. Możemy wywnioskować, że jest coś nie tak z łączeniem tych złączeń i grupowaniem ich w jednym monolitycznym zapytaniu.

Przykład, jeśli masz trzy tabele, a mianowicie app(files), ios_app(dm_data), android_app(kc_data), a to są dane na przykład dla 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)

A to są dane dla Twojego Androida:

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)    

Jeśli użyjesz tylko tego zapytania:

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

Zamiast tego dane wyjściowe będą nieprawidłowe:

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

Możesz myśleć o sprzężeniach łańcuchowych jako o produkcie kartezjańskim, więc jeśli masz 3 wiersze w pierwszej tabeli i 2 wiersze w drugiej tabeli, wynik będzie równy 6

Oto wizualizacja, zobacz, że są 2 powtarzające się AB Androida dla każdego AB ios. Istnieją 3 ios AB, więc jaka byłaby liczba, gdy zrobisz COUNT(ios_app.date_released)? To będzie 6; to samo z COUNT(android_app.date_released) , będzie to również 6. Podobnie są 4 powtarzające się TR androida na każdy ios TR, w ios są 2 TR, więc to daje nam liczbę 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)

Więc to, co powinieneś zrobić, to spłaszczyć każdy wynik, zanim połączysz go z innymi tabelami i zapytaniami.

Jeśli Twoja baza danych obsługuje CTE, użyj tak. To bardzo zgrabne i bardzo samodokumentujące:

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;

Natomiast jeśli Twoja baza danych nie ma jeszcze funkcji CTE, tak jak MySQL, powinieneś zrobić to:

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

To zapytanie i zapytanie w stylu CTE pokażą prawidłowe dane wyjściowe:

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

Test na żywo

Nieprawidłowe zapytanie:http://www.sqlfiddle.com/#!2/9774a/ 2

Prawidłowe zapytanie: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. Rozszerzanie klas w bazie danych

  2. Jak znaleźć najpopularniejsze wystąpienia słów w MySQL?

  3. Python konwertujący wynik zapytania mysql na json

  4. pojawia się błąd podczas definiowania nazwy zdarzenia w mysqlworkbench 5.5

  5. Uzyskaj nazwy tabel za pomocą instrukcji SELECT w MySQL