Vous devez aplatir les résultats de votre requête, afin d'obtenir un décompte juste.
Vous avez dit que vous avez une relation un-à-plusieurs entre votre table de fichiers et d'autres tables
Si SQL n'a qu'un mot-clé LOOKUP
au lieu de tout caser dans JOIN
mots-clés, il doit être facile de déduire si la relation entre la table A et la table B est un-à-un, en utilisant JOIN
connote automatiquement un-à-plusieurs. Je digresse. Quoi qu'il en soit, j'aurais déjà dû en déduire que vos fichiers sont un à plusieurs contre dm_data; et aussi, les fichiers contre kc_data sont aussi un à plusieurs. LEFT JOIN
est un autre indice que la relation entre la première table et la deuxième table est un-à-plusieurs ; ce n'est pas définitif cependant, certains codeurs écrivent simplement tout avec LEFT JOIN
. Il n'y a rien de mal avec votre LEFT JOIN dans votre requête, mais s'il y a plusieurs tables un-à-plusieurs dans votre requête, cela échouera sûrement, votre requête produira des lignes répétées par rapport à d'autres lignes.
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
Donc, avec cette connaissance, vous indiquez que les fichiers sont un à plusieurs contre dm_data, et c'est aussi un à plusieurs contre kc_data. Nous pouvons en conclure qu'il y a quelque chose de mal à enchaîner ces jointures et à les regrouper sur une requête monolithique.
Un exemple si vous avez trois tables, à savoir app(files), ios_app(dm_data), android_app(kc_data), et voici les données par exemple pour 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)
Et voici les données pour votre 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)
Si vous utilisez simplement cette requête :
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
La sortie sera erronée :
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
Vous pouvez considérer les jointures chaînées comme un produit cartésien, donc si vous avez 3 lignes sur la première table et 2 lignes sur la deuxième table, la sortie sera 6
Voici la visualisation, voyez qu'il y a 2 répétitions Android AB pour chaque ios AB. Il y a 3 ios AB, alors quel serait le décompte lorsque vous feriez COUNT(ios_app.date_released) ? Cela deviendra 6; pareil avec COUNT(android_app.date_released)
, ce sera également 6. De même, il y a 4 TR android répétés pour chaque TR ios, il y a 2 TR dans ios, donc cela nous donnerait un compte de 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)
Donc, ce que vous devez faire est d'aplatir chaque résultat avant de les joindre à d'autres tables et requêtes.
Si votre base de données est capable de CTE, veuillez l'utiliser. C'est très soigné et très auto-documenté :
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;
Alors que si votre base de données n'a pas encore de capacité CTE, comme MySQL, vous devriez faire ceci à la place :
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
Cette requête et la requête de style CTE afficheront le résultat correct :
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
Test en direct
Requête incorrecte :http://www.sqlfiddle.com/#!2/9774a/ 2
Requête correcte :http://www.sqlfiddle.com/#!2/9774a/ 1