U moet de resultaten afvlakken van uw vraag, om een juiste telling te verkrijgen.
Je zei dat je een een-op-veel-relatie hebt van je bestandentabel naar andere tafel(s)
Als SQL alleen een trefwoord heeft LOOKUP
in plaats van alles in JOIN
te proppen trefwoorden, moet het gemakkelijk zijn om af te leiden of de relatie tussen tabel A en tabel B één-op-één is, met behulp van JOIN
zal automatisch een-op-veel betekenen. Ik dwaal af. Hoe dan ook, ik had al moeten concluderen dat je bestanden een-op-veel zijn tegen dm_data; en ook de bestanden tegen kc_data zijn ook één-op-veel. LEFT JOIN
is nog een hint dat de relatie tussen de eerste tabel en de tweede tabel een-op-veel is; dit is echter niet definitief, sommige programmeurs schrijven alles gewoon met LEFT JOIN
. Er is niets mis met uw LEFT JOIN in uw zoekopdracht, maar als er meerdere een-op-veel-tabellen in uw zoekopdracht zijn, zal dat zeker mislukken, uw zoekopdracht zal herhalende rijen produceren tegen andere rijen.
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
Dus met deze wetenschap dat je aangeeft dat bestanden één-op-veel zijn tegen dm_data, en het is ook één-op-veel tegen kc_data. We kunnen concluderen dat er iets mis is met het koppelen van die joins en het groeperen ervan op één monolithische query.
Een voorbeeld als je drie tabellen hebt, namelijk app(files), ios_app(dm_data), android_app(kc_data), en dit zijn bijvoorbeeld de data voor 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)
En dit zijn de gegevens voor je 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)
Als u alleen deze zoekopdracht gebruikt:
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
De uitvoer zal in plaats daarvan verkeerd zijn:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
Je kunt geketende joins zien als een cartesiaans product, dus als je 3 rijen op de eerste tafel hebt en 2 rijen op de tweede tafel, is de output 6
Hier is de visualisatie, zie dat er 2 herhalende Android AB is voor elke ios AB. Er zijn 3 ios AB, dus wat is het aantal als je COUNT(ios_app.date_released) doet? Dat wordt 6; hetzelfde met COUNT(android_app.date_released)
, dit wordt ook 6. Evenzo zijn er 4 herhalende Android TR voor elke ios TR, er zijn 2 TR in ios, dus dat zou ons een telling van 8 geven.
.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)
Dus wat u moet doen, is elk resultaat afvlakken voordat u ze samenvoegt met andere tabellen en query's.
Als uw database CTE aankan, gebruik deze dan. Het is erg netjes en zeer zelfdocumenterend:
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;
Terwijl als uw database nog geen CTE-mogelijkheden heeft, zoals MySQL, u dit in plaats daarvan zou moeten doen:
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
Die zoekopdracht en de zoekopdracht in CTE-stijl zullen de juiste uitvoer tonen:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
Live-test
Onjuiste zoekopdracht:http://www.sqlfiddle.com/#!2/9774a/ 2
Correcte zoekopdracht:http://www.sqlfiddle.com/#!2/9774a/ 1