EXISTS a NOT EXISTS

EXISTS (existuje) se ptá jednodušeji než IN: najde poddotaz aspoň jeden řádek? Pokud ano, EXISTS platí; pokud poddotaz nenajde nic, neplatí. Kteří zákazníci mají nějakou vrácenou objednávku?

SELECT z.jmeno
FROM zakaznici AS z
WHERE EXISTS (
    SELECT *
    FROM objednavky AS o
    WHERE o.zakaznik_id = z.id AND o.stav = 'vraceno'
)
ORDER BY z.jmeno;
jmeno
Matěj Němec
Tomáš Veselý

Všimněte si podmínky v poddotazu: o.zakaznik_id = z.id. Poddotaz se odkazuje na z, tabulku vnějšího dotazu. Takovému poddotazu se říká korelovaný. Sám o sobě se spustit nedá (skončil by chybou no such column: z.id), protože závisí na řádku, o kterém vnější dotaz právě rozhoduje. Představte si, že ho databáze spustí znovu pro každého zákazníka. U Evy Novotné je z.id rovno 1 a poddotaz hledá vrácené objednávky zákazníka 1. Žádnou nenajde, takže Eva ve výsledku není. U Tomáše Veselého najde objednávku 7, takže on ve výsledku je.

Poddotazy z předchozích cvičení se provedly jen jednou a jejich výsledek byl pro všechny řádky stejný. Korelovaný poddotaz může pro každý řádek dát jinou odpověď. (Databáze ho ve skutečnosti může provádět chytřeji, ale výsledek je stejný, jako kdyby ho spouštěla pro každý řádek.)

Na tom, co poddotaz ukazuje, nezáleží: EXISTS jen zjišťuje, jestli nějaký řádek existuje. Proto tam programátoři píšou SELECT * nebo SELECT 1.

NOT EXISTS platí, když poddotaz nenajde nic. Tohle jsou zákazníci, kteří obchod nikomu nedoporučili, tedy otázka, která s NOT IN spadla do pasti:

SELECT z.jmeno
FROM zakaznici AS z
WHERE NOT EXISTS (
    SELECT *
    FROM zakaznici AS d
    WHERE d.doporucil = z.id
)
ORDER BY z.jmeno;
jmeno
Anna Kučerová
Filip Beneš
Kristýna Fialová
…

NOT EXISTS žádnou past s NULL nemá: zákazník, který má ve sloupci doporucil hodnotu NULL, prostě nikdy nesplní podmínku d.doporucil = z.id. Vnější dotaz i poddotaz tu používají stejnou tabulku, takže aliasy z a d jsou nutné: říkají, který zákazník je který.

Typická chyba: zapomenout na podmínku, která poddotaz spojuje s řádkem vnějšího dotazu. WHERE EXISTS (SELECT * FROM objednavky WHERE stav = 'vraceno') se ptá, jestli existuje vůbec nějaká vrácená objednávka. Ta existuje, takže podmínka platí pro každého zákazníka a dotaz ukáže všech 14.

Pokyny

Dotaz v editoru najde hry, které si nikdo nekoupil, pomocí LEFT JOIN … IS NULL, jak jste se naučili v 6. lekci. Přepište ho pomocí NOT EXISTS: nechte hry, pro které poddotaz nenajde v tabulce polozky žádný řádek s ID hry. Výsledek zůstane stejný:

nazev
Lost Temple
Mystery Manor
Robot Rebellion

Pod něj ukažte název a cenu her, které si někdo koupil levněji, než je cena hry, tedy ve slevě. Použijte EXISTS: poddotaz hledá řádek tabulky polozky s touto hrou, jehož cena je nižší než cena hry. Sloupec cena mají obě tabulky, takže na aliasech záleží. Seřaďte podle názvu:

nazevcena
Shadow Ninja649
Zombie Town799

Nakonec pomocí NOT EXISTS ukažte jméno a datum registrace (registrace) zákazníků, kteří v roce 2024 nezadali žádnou objednávku. Seřaďte je podle data registrace:

jmenoregistrace
Natálie Marková2024-08-14
Adéla Králová2025-02-12
Filip Beneš2025-05-06
Kristýna Fialová2025-08-21
Martin Zeman2025-10-03

Začněte programovat zdarma

Registrací souhlasíte s provozními podmínkami a zásadami ochrany osobních údajů.

Nebo se registrujte pomocí:

4/8