Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySql:Multiple Left Join gibt falsche Ausgabe

Sie müssen die Ergebnisse glätten Ihrer Anfrage, um eine richtige Zählung zu erhalten.

Sie sagten, Sie haben eine Eins-zu-Viele-Beziehung von Ihrer Dateitabelle zu anderen Tabellen

Wenn SQL nur ein Schlüsselwort LOOKUP hat anstatt alles in JOIN zu stopfen Schlüsselwörtern sollte es einfach sein, mit JOIN abzuleiten, ob die Beziehung zwischen Tabelle A und Tabelle B eine Eins-zu-Eins-Beziehung ist wird automatisch eins-zu-vielen bedeuten. Ich schweife ab. Wie auch immer, ich hätte bereits schließen sollen, dass Ihre Dateien Eins-zu-Viele gegen dm_data sind; und auch die Dateien gegen kc_data sind ebenfalls One-to-Many. LEFT JOIN ist ein weiterer Hinweis darauf, dass die Beziehung zwischen der ersten Tabelle und der zweiten Tabelle eine Eins-zu-Viele ist; Dies ist jedoch nicht endgültig, einige Programmierer schreiben einfach alles mit LEFT JOIN . An Ihrem LEFT JOIN in Ihrer Abfrage ist nichts auszusetzen, aber wenn Ihre Abfrage mehrere Eins-zu-Viele-Tabellen enthält, wird dies sicherlich fehlschlagen, da Ihre Abfrage sich wiederholende Zeilen gegen andere Zeilen erzeugen wird.

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

Mit diesem Wissen geben Sie also an, dass Dateien eins zu vielen gegen dm_data sind, und es ist auch eins zu vielen gegen kc_data. Wir können daraus schließen, dass etwas falsch daran ist, diese Joins zu verketten und sie in einer monolithischen Abfrage zu gruppieren.

Ein Beispiel, wenn Sie drei Tabellen haben, nämlich app(files), ios_app(dm_data), android_app(kc_data), und dies sind die Daten zum Beispiel für 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)

Und das sind die Daten für Ihr Android:

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)    

Wenn Sie nur diese Abfrage verwenden:

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

Die Ausgabe wird stattdessen falsch sein:

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

Sie können sich verkettete Joins als kartesisches Produkt vorstellen. Wenn Sie also 3 Zeilen in der ersten Tabelle und 2 Zeilen in der zweiten Tabelle haben, ist die Ausgabe 6

Hier ist die Visualisierung, sehen Sie, dass es 2 sich wiederholende Android-ABs für jeden ios-AB gibt. Es gibt 3 ios AB, was wäre also die Zählung, wenn Sie COUNT(ios_app.date_released) ausführen? Das wird 6; dasselbe gilt für COUNT(android_app.date_released) , dies wird auch 6 sein. Ebenso gibt es 4 sich wiederholende Android-TR für jede ios-TR, es gibt 2 TR in ios, sodass wir eine Zählung von 8 erhalten würden.

.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)

Sie sollten also jedes Ergebnis glätten, bevor Sie es mit anderen Tabellen und Abfragen verbinden.

Wenn Ihre Datenbank CTE-fähig ist, verwenden Sie dies bitte. Es ist sehr ordentlich und sehr selbstdokumentierend:

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;

Wenn Ihre Datenbank dagegen noch keine CTE-Fähigkeit hat, wie MySQL, sollten Sie stattdessen Folgendes tun:

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

Diese Abfrage und die Abfrage im CTE-Stil zeigen die korrekte Ausgabe:

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

Live-Test

Falsche Abfrage:http://www.sqlfiddle.com/#!2/9774a/ 2

Richtige Abfrage:http://www.sqlfiddle.com/#!2/9774a/ 1