Du måste platta ut resultaten av din fråga, för att få rätt räkning.
Du sa att du har en-till-många-relationer från din filtabell till andra tabeller
Om SQL bara har nyckelordet LOOKUP
istället för att stoppa in allt i JOIN
nyckelord, ska det vara lätt att sluta sig till om relationen mellan tabell A och tabell B är en-till-en, med JOIN
kommer automatiskt att antyda en-till-många. Jag avviker. Hur som helst, jag borde redan ha dragit slutsatsen att dina filer är en-till-många mot dm_data; och även filerna mot kc_data är en-till-många också. LEFT JOIN
är ett annat tips om att förhållandet mellan första bordet och andra bordet är en-till-många; detta är dock inte definitivt, vissa kodare skriver bara allt med LEFT JOIN
. Det är inget fel med din LEFT JOIN i din fråga, men om det finns flera en-till-många-tabeller i din fråga, kommer det säkert att misslyckas, din fråga kommer att producera upprepade rader mot andra rader.
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
Så med denna kunskap att du indikerar att filer är en-till-många mot dm_data, och det är en-till-många även mot kc_data. Vi kan dra slutsatsen att det är något fel med att kedja dessa sammanfogningar och gruppera dem i en monolitisk fråga.
Ett exempel om du har tre tabeller, nämligen app(filer), ios_app(dm_data), android_app(kc_data), och detta är data till exempel 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)
Och detta är data för din 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)
Om du bara använder den här frågan:
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
Utdata blir fel istället:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
Du kan tänka på kedjade kopplingar som kartesiska produkter, så om du har 3 rader på det första bordet och har 2 rader på det andra bordet, blir resultatet 6
Här är visualiseringen, se att det finns 2 repeterande android AB för varje ios AB. Det finns 3 ios AB, så vad skulle antalet vara när du gör COUNT(ios_app.date_released)? Det blir 6; samma sak med COUNT(android_app.date_released)
, detta kommer också att vara 6. På samma sätt finns det 4 upprepade Android TR för varje ios TR, det finns 2 TR i iOS, så det skulle ge oss ett antal 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)
Så vad du bör göra är att platta ut varje resultat innan du kopplar dem till andra tabeller och frågor.
Om din databas är kapabel till CTE, använd det. Det är väldigt snyggt och väldigt självdokumenterande:
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;
Om din databas inte har någon CTE-kapacitet ännu, som MySQL, bör du göra detta istället:
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
Den frågan och frågan i CTE-stil visar korrekt utdata:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
Livetest
Felaktig fråga:http://www.sqlfiddle.com/#!2/9774a/ 2
Korrekt fråga:http://www.sqlfiddle.com/#!2/9774a/ 1