12. Poddotazy
Poddotazy neboli vnořené dotazy jsou umístěny uvnitř jiného hlavního dotazu a výsledky z nich se dále využívají v tomto dotazu hlavním. Nejčastější použití poddotazu je v klauzuli WHERE, nahrazení některé ze spojovaných tabulek v hlavním dotazu nebo přímo získání hodnoty pro každý řádek. V tomto článku si ukážeme všechna tato použití.Poddotaz jako součást podmínky
V jednom z předchozích dílů jsme si představovali operátor IN. Ten nám umožnoval určit pevný výčet hodnot, kterým se má daný sloupec rovnat. IN můžeme můžeme použít v kombinaci s poddotazem. Místo pevného výčtu určíme hodnoty právě tímto vnořeným dotazem. Vyzkoušíme si to na databázi vytvořené v minulých dílech tutoriálu:SELECT knihy.* FROM `knihy`
WHERE knihy.kniha_id IN
(SELECT vydani_knihy.kniha_id FROM vydani_knihy WHERE vydani_knihy.rok >= 2014);
Tímto dotazem zjistíme všechny knihy, jejichž vydání je z roku 2014 a novější. Samotný poddotaz nám z tabulky vydani_knihy vrátí seznam knihy_id, které splňují podmínku s rokem vydání. Hlavní dotaz pak vybere knihy, jejichž kniha_id patří do takto získaného seznamu:
+----------+------------------+ | kniha_id | nazev | +----------+------------------+ | 1 | Duna | | 2 | Malý princ | | 4 | Svět ledu a ohně | +----------+------------------+
V hlavním dotazu i poddotazu můžeme bez problémů využívat spojování tabulek.
Při pohledu na tento dotaz a jeho výsledek Vás možná napadlo že stejného výsledku docílíme i běžným spojením tabulek pomocí JOIN. V tomto případě tomu tak skutečně je, ale není možné to tak říci obecně. Jsou situace kdy poddotaz spojením tabulek nahradit nelze.
Poddotaz jako tabulka v hlavním dotazu
Když za klíčovým slovem WHERE vyjmenováváme tabulky, můžeme jednu či více z nich nahradit poddotazem. Výsledek poddotazu je totiž vlastně taky tabulka a my s ní můžeme tak pracovat. Zkusíme takto získat podobný výsledek jako v předchozím příkladu:SELECT knihy.*
FROM `knihy` JOIN (select kniha_id FROM vydani_knihy WHERE rok >= 2014) AS vydani
ON vydani.kniha_id = knihy.kniha_id;
V poddotazu získáme podčást tabulky vydani_knihy omezenou rokem vydání. Takto získanou tabulku pak pomocí JOIN spojíme s tabulkou knihy a dostaneme:
+----------+------------------+ | kniha_id | nazev | +----------+------------------+ | 1 | Duna | | 1 | Duna | | 2 | Malý princ | | 2 | Malý princ | | 4 | Svět ledu a ohně | +----------+------------------+
Výsledek se mírně liší od předchozího. Pokud měla kniha více vydání splňujících podmínku, je zde uvedena opakovaně, ale i to by šlo další modifikací dotazu vyřešit. Za poddotazem můžete vidět nové klíčové slovo AS které slouží k vytvoření aliasu. Detailněji si o něm ještě povíme v dalších článcích.
Poddotaz jako získání hodnoty v každém řádku
Třetí možností jak využít poddotaz je získání hodnoty pro každý řádek. Nejčastěji to bude v kombinací s nějakou agregační funkcí. V našem případě si vypíšeme počet hodnocení které máme uložené pro každou knihu:SELECT knihy.nazev, (SELECT COUNT(hodnoceni_id)
FROM hodnoceni
WHERE hodnoceni.kniha_id = knihy.kniha_id) as pocet_hodnoceni
FROM knihy;
+------------------+-----------------+ | nazev | pocet_hodnoceni | +------------------+-----------------+ | Duna | 6 | | Malý princ | 5 | | Záskok | 0 | | Svět ledu a ohně | 3 | +------------------+-----------------+
Při tomto použítí poddotazu se narozdíl od předchozích musí pro každý řádek vykonat poddotaz znovu. Při 1000 řádcích výsledku to znamená 1000 poddotazů, což už teoreticky může být značný výkonostní problém.
Je tedy nutné dobře se zamyslet, zda-li nám takové toto použítí poddotazu nemůže zůsobit problém a případně řesit dotaz jiným způsobem.
Je tedy nutné dobře se zamyslet, zda-li nám takové toto použítí poddotazu nemůže zůsobit problém a případně řesit dotaz jiným způsobem.
Tolik k tématu poddotazů a v příštím díle se podrobněji podíváme na fulltextové vyhledávání a využítí regulárních výrazů.
Další díly tutoriálu
10. Spojování více tabulek - pokročilé11. Agregační funkce
12. Poddotazy
13. Fulltextové vyhledávání
14. Regulární výrazy