Debe aplanar los resultados de su consulta, con el fin de obtener un conteo correcto.
Dijiste que tienes una relación de uno a muchos desde tu tabla de archivos a otra(s) tabla(s)
Si SQL solo tiene una palabra clave LOOKUP
en lugar de meter todo en JOIN
palabras clave, será fácil inferir si la relación entre la tabla A y la tabla B es uno a uno, usando JOIN
automáticamente connotará uno a muchos. estoy divagando De todos modos, ya debería haber inferido que sus archivos son uno a muchos contra dm_data; y también, los archivos contra kc_data también son de uno a muchos. LEFT JOIN
es otra pista de que la relación entre la primera tabla y la segunda tabla es de uno a muchos; Sin embargo, esto no es definitivo, algunos codificadores simplemente escriben todo con LEFT JOIN
. No hay nada malo con LEFT JOIN en su consulta, pero si hay varias tablas de uno a muchos en su consulta, eso seguramente fallará, su consulta producirá filas repetidas contra otras filas.
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
Entonces, con este conocimiento, indica que los archivos son uno a muchos contra dm_data, y también son uno a muchos contra kc_data. Podemos concluir que hay algo malo en encadenar esas uniones y agruparlas en una consulta monolítica.
Un ejemplo si tiene tres tablas, a saber, aplicación (archivos), ios_app (dm_data), android_app (kc_data), y estos son los datos, por ejemplo, para 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)
Y estos son los datos de tu 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 simplemente usa esta consulta:
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 salida será incorrecta en su lugar:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
Puede pensar en las uniones encadenadas como un producto cartesiano, por lo que si tiene 3 filas en la primera tabla y tiene 2 filas en la segunda tabla, la salida será 6
Aquí está la visualización, vea que hay 2 Android AB repetitivos para cada ios AB. Hay 3 ios AB, entonces, ¿cuál sería el conteo cuando haces COUNT (ios_app.date_released)? Eso se convertirá en 6; lo mismo con COUNT(android_app.date_released)
, esto también será 6. Del mismo modo, hay 4 TR repetidos de Android para cada TR de ios, hay 2 TR en iOS, por lo que nos daría una cuenta 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)
Entonces, lo que debe hacer es aplanar cada resultado antes de unirlos a otras tablas y consultas.
Si su base de datos es compatible con CTE, utilícelo. Es muy ordenado y muy autodocumentado:
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;
Mientras que si su base de datos aún no tiene capacidad CTE, como MySQL, debe hacer esto en su lugar:
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
Esa consulta y la consulta de estilo CTE mostrarán el resultado correcto:
app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 3 | 2
MK | 0 | 1
PM | 0 | 0
TR | 2 | 4
(4 rows)
Prueba en vivo
Consulta incorrecta:http://www.sqlfiddle.com/#!2/9774a/ 2
Consulta correcta:http://www.sqlfiddle.com/#!2/9774a/ 1