sql >> Base de Datos >  >> RDS >> Mysql

MySql:Multiple Left Join dando salida incorrecta

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