sql >> Databáze >  >> RDS >> Mysql

MySql:Vícenásobné levé spojení dává nesprávný výstup

Musíte vyrovnat výsledky vašeho dotazu, abyste získali správný počet.

Řekl jste, že máte vztah jedna k mnoha z vaší tabulky souborů k jiným tabulkám

Pokud má SQL pouze klíčové slovo LOOKUP místo toho, abyste vše nacpali do JOIN klíčová slova, bude snadné odvodit, zda je vztah mezi tabulkou A a tabulkou B jedna ku jedné, pomocí JOIN bude automaticky znamenat jeden k mnoha. jsem odbočil. V každém případě jsem měl již odvodit, že vaše soubory jsou proti dm_data srovnatelné; a také soubory proti kc_data jsou také jeden k mnoha. LEFT JOIN je další nápověda, že vztah mezi první tabulkou a druhou tabulkou je jedna k mnoha; to však není definitivní, někteří kodéři prostě vše zapisují pomocí LEFT JOIN . Na vašem LEFT JOIN ve vašem dotazu není nic špatného, ​​ale pokud je ve vašem dotazu více tabulek one-to-many, určitě to selže, váš dotaz bude vytvářet opakující se řádky proti jiným řádkům.

from
    files
        left join
    dm_data ON dm_data.id = files.id
        left join
    kc_data ON kc_data.id = files.id

Takže s tímto vědomím, že uvádíte, že jsou soubory jedna k mnoha proti dm_data, a je také proti kc_data jedna k mnoha. Můžeme dojít k závěru, že na řetězení těchto spojení a jejich seskupování do jednoho monolitického dotazu není něco v pořádku.

Příklad, pokud máte tři tabulky, jmenovitě app(files), ios_app(dm_data), android_app(kc_data), a toto jsou data například pro 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)

A toto jsou data pro váš 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)    

Pokud použijete pouze tento dotaz:

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

Místo toho bude výstup chybný:

 app_code | ios_release_count | android_release_count 
----------+-------------------+-----------------------
 AB       |                 6 |                     6
 MK       |                 0 |                     1
 PM       |                 0 |                     0
 TR       |                 8 |                     8
(4 rows)

Zřetězená spojení si můžete představit jako kartézský součin, takže pokud máte 3 řádky na první tabulce a 2 řádky na druhé tabulce, výstup bude 6

Zde je vizualizace, podívejte se, že existují 2 opakující se android AB pro každý ios AB. Existují 3 ios AB, takže jaký by byl počet, když uděláte COUNT(ios_app.date_released)? To bude 6; totéž s COUNT(android_app.date_released) , toto bude také 6. Stejně tak existují 4 opakující se android TR pro každý ios TR, v ios jsou 2 TR, takže by nám to dalo 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)

Takže co byste měli udělat, je srovnat každý výsledek, než je připojíte k jiným tabulkám a dotazům.

Pokud vaše databáze podporuje CTE, použijte jej. Je to velmi úhledné a velmi dokumentující:

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;

Zatímco pokud vaše databáze ještě nemá schopnost CTE, jako je MySQL, měli byste místo toho udělat toto:

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

Tento dotaz a dotaz ve stylu CTE zobrazí správný výstup:

 app_code | ios_release_count | android_release_count 
----------+-------------------+-----------------------
 AB       |                 3 |                     2
 MK       |                 0 |                     1
 PM       |                 0 |                     0
 TR       |                 2 |                     4
(4 rows)

Živý test

Nesprávný dotaz:http://www.sqlfiddle.com/#!2/9774a/ 2

Správný dotaz:http://www.sqlfiddle.com/#!2/9774a/ 1



  1. Nelze se připojit k MySQL prostřednictvím EF6 ve Visual Studiu 2013

  2. převod datového typu varchar na datový typ datetime vedl k hodnotě mimo rozsah

  3. Výsledek převodu čísel na slova v MYSQL! Pomocí Query

  4. MySQL efektivně ukládá neorientované okraje grafu