🤝 Spojování tabulek (JOIN)

Slepení tabulek

O čem to je

V tabulce známek je jen číslo žáka, třeba 2. Učitelka ale chce vidět „Petr – M – 3“, ne „2 – M – 3“. Jméno je v jiné tabulce. Musí obě tabulky „slepit“ podle čísla žáka.

Kvůli normalizaci jsou data rozdělená do více tabulek. Při čtení je zase skládáme dohromady. Na to slouží spojování tabulek, anglicky JOIN. Je to nejdůležitější dovednost práce s SQL.

Nové pojmy

Primární a cizí klíčPřipomenutí: primární klíč jednoznačně určuje řádek (zaci.id). Cizí klíč na něj odkazuje z jiné tabulky (znamky.id_zaka).Známka s id_zaka = 2 patří žákovi s id = 2.
Spojení JOIN … ON …Ke každému řádku jedné tabulky připojí řádky druhé tabulky, pro které platí podmínka za ON. Podmínka obvykle porovná cizí klíč s primárním.zaci JOIN znamky ON zaci.id = znamky.id_zaka
Vnitřní spojení INNER JOINVrátí jen dvojice řádků, které k sobě našly protějšek. Slovo INNER se smí vynechat, samotné JOIN znamená totéž.Žák bez známek ve výsledku nebude.
Alias tabulkyKrátké jméno tabulky v dotazu. Píše se za název tabulky. Sloupec se pak zapisuje alias.sloupec.FROM zaci z → z.jmeno

Dvě tabulky

idjmenotrida
1Eva2.A
2Petr2.A
3Jana3.B
4Tomáš3.B
5Lucie1.C
idid_zakapredmetznamka
11M1
21ČJ2
32M3
42ČJ4
53M2
64ČJ1
72M5

Dotaz

  • SELECT z.jmeno, k.predmet, k.znamka
  • FROM zaci z
  • JOIN znamky k ON z.id = k.id_zaka
  • WHERE z.trida = '2.A';
Pro každý řádek žáka najdi známky, kde k.id_zaka = z.id.
Z každé nalezené dvojice vznikne jeden řádek výsledku.
WHERE nechá jen žáky z 2.A.
Výsledek: Eva M 1, Eva ČJ 2, Petr M 3, Petr ČJ 4, Petr M 5.
Kolik řádků vrátí SELECT * FROM zaci z JOIN znamky k ON z.id = k.id_zaka; (bez WHERE)?
Každá známka najde právě jednoho žáka. Řádků je tolik jako známek: 7. Lucie (id 5) nemá žádnou známku, ve výsledku vnitřního spojení není.
Vypiš průměr každého žáka i se jménem.
SELECT z.jmeno, AVG(k.znamka) FROM zaci z JOIN znamky k ON z.id = k.id_zaka GROUP BY z.id, z.jmeno; Nejdřív spojení, pak seskupení. Výsledek: Eva 1.5, Petr 4, Jana 2, Tomáš 1.
✗SELECT jmeno, znamka FROM zaci, znamky;
✓SELECT jmeno, znamka FROM zaci JOIN znamky ON zaci.id = znamky.id_zaka;

Bez podmínky spojení se každý žák spojí s každou známkou (5 · 7 = 35 řádků). Většina dvojic nedává smysl.

JOIN … ON spojí řádky dvou tabulek podle podmínky, nejčastěji cizí klíč = primární klíč. Vnitřní spojení vrátí jen řádky, které mají protějšek. Aliasy (zaci z) zkracují zápis.

Druhy spojení

O čem to je

Učitelka chce seznam všech žáků se známkami. I Lucii, která zatím žádnou známku nemá, aby nezapomněla ji vyzkoušet. Obyčejné JOIN by Lucii vynechalo. Pro takové případy existují vnější spojení.

Druhy spojení si nejlépe představíš jako dvě překrývající se množiny: žáky a známky. Každý druh spojení vybere jinou část.

Nové pojmy

Spojení tabulek (JOIN)Skládá řádky ze dvou tabulek podle podmínky za ON, obvykle cizí klíč = primární klíč.zaci z JOIN znamky k ON z.id = k.id_zaka
Levá a pravá tabulkaLevá je tabulka uvedená před slovem JOIN, pravá za ním.V zaci LEFT JOIN znamky je levá zaci.
Vnější spojení (OUTER JOIN)Vrátí i řádky bez protějšku. Chybějící hodnoty druhé tabulky doplní jako NULL. Slovo OUTER se smí vynechat.Lucie se ve výsledku objeví se známkou NULL.
Kartézský součin (CROSS JOIN)Spojí každý řádek jedné tabulky s každým řádkem druhé. Počet řádků = součin počtů.5 žáků × 7 známek = 35 řádků.
SpojeníCo vrátíPro žáky a známky
INNER JOINjen řádky s protějškem7 řádků, Lucie chybí
LEFT JOINvšechny řádky levé tabulky + protějšky (nebo NULL)8 řádků, Lucie s NULL
RIGHT JOINvšechny řádky pravé tabulky + protějšky (nebo NULL)jako LEFT, jen strany obráceně
FULL OUTER JOINvšechny řádky obou tabuleknepodporuje např. MySQL
CROSS JOINkaždý s každým35 řádků

Roztřiď úlohy: stačí vnitřní spojení, nebo potřebuješ i řádky bez protějšku?

Kdo nemá známku

  • SELECT z.jmeno
  • FROM zaci z
  • LEFT JOIN znamky k ON z.id = k.id_zaka
  • WHERE k.id IS NULL;

LEFT JOIN ponechá všechny žáky. U Lucie nenašel žádnou známku, proto jsou sloupce známek NULL. WHERE k.id IS NULL nechá právě takové žáky. Výsledek: Lucie.

Kolik řádků vrátí SELECT * FROM zaci z LEFT JOIN znamky k ON z.id = k.id_zaka;?
Žáci se známkami dají 7 řádků (jako INNER JOIN). Lucie bez známky přidá 1 řádek s NULL. Celkem 8.
Spojení tří tabulek: zaci, zak_krouzek(id_zaka, id_krouzku) a krouzky(id, nazev). Vypiš jména žáků a názvy kroužků.
SELECT z.jmeno, kr.nazev FROM zaci z JOIN zak_krouzek zk ON z.id = zk.id_zaka JOIN krouzky kr ON kr.id = zk.id_krouzku; Vazební tabulka je uprostřed, na každé straně jedno JOIN.
✗… LEFT JOIN znamky k ON z.id = k.id_zaka WHERE k.predmet = 'M' vrátí všechny žáky.
✓Chceš-li všechny žáky a jen známky z M, dej podmínku do ON: ON z.id = k.id_zaka AND k.predmet = 'M'.

U žáků bez známky z M je k.predmet NULL a podmínka ve WHERE je vyřadí. Z LEFT JOIN se tak nechtěně stane vnitřní spojení.

INNER JOIN vrátí jen řádky s protějškem, LEFT JOIN všechny řádky levé tabulky (chybějící doplní NULL), RIGHT JOIN pravé, FULL OUTER JOIN obou. CROSS JOIN spojí každý řádek s každým.