Devi appiattire i risultati della tua richiesta, al fine di ottenere un conteggio corretto.
Hai detto di avere una relazione uno-a-molti dalla tabella dei file ad altre tabelle
Se SQL ha solo una parola chiave LOOKUP
invece di stipare tutto in JOIN
parole chiave, sarà facile dedurre se la relazione tra la tabella A e la tabella B è uno a uno, utilizzando JOIN
connota automaticamente uno a molti. Io divago. Ad ogni modo, avrei già dovuto dedurre che i tuoi file sono uno a molti contro dm_data; e inoltre, anche i file contro kc_data sono uno a molti. LEFT JOIN
è un altro suggerimento che la relazione tra la prima tabella e la seconda tabella è uno a molti; questo non è definitivo però, alcuni programmatori scrivono semplicemente tutto con LEFT JOIN
. Non c'è niente di sbagliato nel tuo LEFT JOIN nella tua query, ma se ci sono più tabelle da uno a molti nella tua query, ciò sicuramente fallirà, la tua query produrrà righe ripetute rispetto ad altre righe.
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
Quindi, con questa consapevolezza che indichi che i file sono uno a molti contro dm_data, ed è uno a molti anche contro kc_data. Possiamo concludere che c'è qualcosa di sbagliato nel concatenare quei join e raggrupparli su una query monolitica.
Un esempio se hai tre tabelle, vale a dire app(files), ios_app(dm_data), android_app(kc_data), e questi sono i dati ad esempio per 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)
E questi sono i dati per il tuo 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)
Se usi semplicemente questa query:
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
L'output sarà invece sbagliato:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
Puoi pensare ai join concatenati come un prodotto cartesiano, quindi se hai 3 righe sulla prima tabella e 2 righe sulla seconda tabella, l'output sarà 6
Ecco la visualizzazione, vedi che ci sono 2 AB Android ripetuti per ogni AB ios. Ci sono 3 ios AB, quindi quale sarebbe il conteggio quando esegui COUNT(ios_app.date_released)? Quello diventerà 6; lo stesso con COUNT(android_app.date_released)
, anche questo sarà 6. Allo stesso modo ci sono 4 TR Android ripetuti per ogni TR ios, ci sono 2 TR in ios, quindi questo ci darebbe un conteggio di 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)
Quindi quello che dovresti fare è appiattire ogni risultato prima di unirlo ad altre tabelle e query.
Se il tuo database è in grado di supportare CTE, utilizzalo. È molto pulito e molto auto-documentante:
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;
Considerando che se il tuo database non ha ancora funzionalità CTE, come MySQL, dovresti invece farlo:
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
Quella query e la query in stile CTE mostreranno l'output corretto:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
Test dal vivo
Query errata:http://www.sqlfiddle.com/#!2/9774a/ 2
Query corretta:http://www.sqlfiddle.com/#!2/9774a/ 1