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