Záludnosti spojování

Spojení jsou mocná, a proto jsou jejich chyby nebezpečné: většina z nich neskončí chybou, jen dá špatný výsledek, který vypadá věrohodně. Tady jsou tři nejčastější.

1. Zapomenuté ON. SQLite vás nechá napsat JOIN bez podmínky. Pak nic neříká, které řádky k sobě patří, a tak spáruje každý řádek levé tabulky s každým řádkem pravé:

SELECT COUNT(*) AS pocet_radku
FROM zakaznici AS z
JOIN objednavky AS o;
pocet_radku
420

14 zákazníků krát 30 objednávek: 420 řádků, všechny možné kombinace. Takovému spojení se říká kartézský součin (anglicky cross join). Někdy je to přesně to, co chcete (třeba každý zákazník s každou hrou), ale obvykle je to zapomenuté ON. Když má výsledek mnohem víc řádků, než jste čekali, zkontrolujte ON u každého spojení. Můžete se setkat i se starším způsobem spojování, kdy jsou tabulky oddělené čárkami a podmínka je ve WHERE: FROM zakaznici z, objednavky o WHERE o.zakaznik_id = z.id. Když tam zapomenete WHERE, dostanete stejných 420 řádků.

2. Řádky, které se násobí. Spojení dá řádek pro každou dvojici. Když ke hrám připojíte dvě tabulky najednou, třeba recenze a položky objednávek, spáruje se každá recenze hry s každou její položkou. Dragon Forge má 4 recenze a byla ve 4 objednávkách:

SELECT h.nazev, COUNT(r.hvezdicky) AS pocet_recenzi, SUM(p.pocet) AS kusy
FROM hry AS h
JOIN recenze AS r ON r.hra_id = h.id
JOIN polozky AS p ON p.hra_id = h.id
WHERE h.id = 1
GROUP BY h.id, h.nazev;
nazevpocet_recenzikusy
Dragon Forge1616

16 recenzí a 16 kusů, čtyřikrát víc, než je pravda: každá ze 4 recenzí se potkala s každou ze 4 položek, a to je 16 řádků. Nic vám neřekne, že je něco špatně, čísla jsou prostě moc velká. Počet se dá zachránit pomocí COUNT(DISTINCT …) klíče: každá recenze patří jednomu zákazníkovi (klíč tabulky recenze je hra a zákazník), takže COUNT(DISTINCT r.zakaznik_id) započítá každou recenzi jednou, bez ohledu na to, kolikrát se její řádek opakoval. Součet se takhle zachránit nedá, protože dvě různé položky můžou mít stejný počet kusů. Spočítejte ho samostatným dotazem, nebo poddotazem, který se naučíte v příští lekci.

3. Podmínka v ON, nebo ve WHERE. U JOIN nezáleží na tom, jestli je podmínka v ON, nebo ve WHERE. U LEFT JOIN ano. Kolik pětihvězdičkových recenzí má která hra?

SELECT h.nazev, COUNT(r.hvezdicky) AS pet_hvezdicek
FROM hry AS h
LEFT JOIN recenze AS r ON r.hra_id = h.id
WHERE r.hvezdicky = 5
GROUP BY h.id, h.nazev
ORDER BY h.nazev;
nazevpet_hvezdicek
Cube Logic1
Dragon Forge2
Knight's Oath1
……

Hry bez pětihvězdičkové recenze chybí, přestože právě kvůli nim tam LEFT JOIN je. WHERE se provádí až po spojení: řádky s NULL ani řádky ostatních recenzí podmínkou r.hvezdicky = 5 neprojdou a WHERE je vyhodí, i s jejich hrami. Podmínka patří do ON:

SELECT h.nazev, COUNT(r.hvezdicky) AS pet_hvezdicek
FROM hry AS h
LEFT JOIN recenze AS r ON r.hra_id = h.id AND r.hvezdicky = 5
GROUP BY h.id, h.nazev
ORDER BY h.nazev;
nazevpet_hvezdicek
Bakery Story0
Castle Siege0
Cube Logic1
……

Podmínka v ON rozhoduje, které řádky pravé tabulky se počítají jako protějšek, a LEFT JOIN si každý řádek levé tabulky nechá tak jako tak: hra bez pětihvězdičkové recenze zůstane, s hodnotami NULL, a COUNT jí dá 0. U LEFT JOIN tedy podmínka na pravou tabulku patří do ON a podmínka na levou tabulku do WHERE.

Pokyny

Každý ze tří dotazů v editoru má jednu ze záludností a žádný z nich neskončí chybou. První má spočítat recenze každé hry, ale tvrdí, že každá hra jich má 25. Doplňte chybějící podmínku, aby počítal jen recenze dané hry. Hry bez recenze ve výsledku díky JOIN nebudou, a to tu nevadí:

nazevpocet_recenzi
Bakery Story1
Cube Logic2
Dragon Forge4
……

Druhý má ukázat počet recenzí a počet objednávek každé hry, ale některá čísla jsou moc velká: Dragon Forge má 4 recenze a 4 objednávky, ne 16. Opravte počítání pomocí DISTINCT, aby se každá recenze a každá objednávka započítala jednou:

nazevpocet_recenzipocet_objednavek
Bakery Story13
Castle Siege01
Cube Logic23
Dragon Forge44
………

Třetí má ukázat, kolik objednávek zadal každý zákazník v roce 2024, s nulou u zákazníků, kteří nezadali žádnou, ale ti ve výsledku chybějí. Přesuňte podmínku tam, kam patří:

jmenoobjednavky_2024
Adéla Králová0
Anna Kučerová1
Eva Novotná3
Filip Beneš0
……

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

11/12