Přednáška 6 SQL – spojení tabulek
Spojení tabulek Základním principem relačního modelu dat jsou relace modelované prostřednictvím cizích klíčů. Vytváření relací chceme dosáhnout efektivního návrhu databáze a zajištění integrity dat. Klasické (jednoduché) SQL dotazy SELECT již známe. V praxi, ale budeme potřebovat získávat data z více tabulek najednou. Existuje více způsobů jak v dotazu spojit a získat data z více tabulek. Spojení tabulek se označujeme jako JOIN.
Princip činnosti Z hlediska efektivního návrhu modelujeme data podle entit do více tabulek. V koncových aplikacích, které databázi využívají, ale chceme zobrazovat data jinak. Chceme je zobrazit jako informace mající smysl. Viz data a informace v první přednášce. Uvažujme např. tabulku vypisující seznam knih VKOL.
Jednoduchá ukázka Máme tabulku knihy: Tabulka autori: Uživateli by takový pohled na data byl velmi málo užitečný a nepřehledný. Potřebujeme z něj získat informace: výsledek dotazu spojení. kniha_id nazev autor_id 1 Broučci 10 2 Babička 20 autor_id jmeno prijmeni 10 Jan Karafiát 20 Božena Němcová Kniha Autor Broučci Jan Karafiát Babička Božena Němcová
Dotaz spojení SELECT knihy.nazev AS Kniha, // Nejprve vybírám atributy z obou tabulek, které mají být zobrazeny ve výsledku SELECT knihy.nazev AS Kniha, // pokud chci nahradit název sloupce, použiju alias CONCAT (autori.jmeno, ' ', autori.prijmeni) AS Autor // funkce CONCAT spojí dva nebo více atributů v jeden řetězec (Jan ' ' Karafiát) // apostrofy představují mezeru, spojuji teda jméno, mezeru a příjmení FROM knihy, autori // Určuju tabulky zdrojových dat, oddělujeme čárkou – čárkové spojení WHERE knihy.autor_id = autori.autor_id; // Podmínka spojení, porovnávám hodnoty cizího klíče tabulky knihy a primárního klíče tabulky autori. Podmínka samozřejmě může obsahovat i filtrování.
Filtrování ve spojení Dotaz spojení by měl např. ukázat pouze knihy napsané Boženou Němcovou a to ve stejném formátu jako předchozí příklad. Dotaz jednoduše doplníme o další dílčí podmínku. SELECT knihy.nazev AS Kniha, CONCAT (autori.jmeno, ' ', autori.prijmeni) AS Autor FROM knihy, autori WHERE knihy.autor_id = autori.autor_id AND autori.autori_id = 20; Kniha Autor Babička Božena Němcová
Relace M:N Tabulka knihy: Tabulka autori: Vazební tabulka kniha_autor: kniha_id nazev 1 Učitelé a technologie 2 E-learning autor_id jmeno prijmeni 10 Klára Šeďová 20 Jiří Zounek kniha_id autor_id 1 10 20 2
Dotaz spojení SELECT knihy.nazev AS Kniha, CONCAT( autori.jmeno, ' ', autori.prijmeni ) AS Autor FROM knihy, autori, kniha_autor WHERE knihy.kniha_id = kniha_autor.kniha_id AND kniha_autor.autor_id = autori.autor_id; Kniha Autor Učitelé a technologie Klára Šeďová Jiří Zounek E-learning
Agregační funkce Základní - Počet (COUNT), součet (SUM), průměr (AVG), minimum (MIN) a maximum (MAX). Výpočet funkce se provádí buď nad všemi záznamy v odpovědi na dotaz (pokud dotaz neobsahuje GROUP BY) nebo nad každou skupinou určenou GROUP BY. Pro funkce SUM a AVG musí být argument číselného typu, pro funkce MAX a MIN buď číselného typu nebo některého z typů typu DATE, TIME, TIMESTAMP, BOOLEAN a řetězec znaků. Mimo to argumentem funkce COUNT smí být také znak *, v takovém případě funkce vrací počet všech hodnot, včetně těch, které se rovnají NULL. Pokud se před argumentem funkce uvede DISTINCT, uvažují se pouze různé hodnoty argumentů (u funkcí MAX a MIN to nemá žádný význam). Agregační funkce se v dotazech používají v klauzuli SELECT nebo HAVING. Nelze je používat v klauzulích WHERE nebo GROUP BY. V klauzuli ORDER BY je nutno je nahradit jménem výsledného sloupce, které lze specifikovat pomocí AS v klauzuli SELECT.
Seskupení v dotazu Klauzule GROUP BY se používá ve spojení s agregačními funkcemi pro seskupení dat do skupin. Např. chceme seskupit počty (COUNT) knih každého autora do jednoho výsledku. Chceme získat toto: Autor Pocet_Knih Šeďová 1 Zounek 2
Seskupení v dotazu SELECT a.prijmeni AS Autor, COUNT (ka.kniha_id) AS Pocet_Knih FROM autori AS a, kniha_autor AS ka WHERE a.autor_id = ka.autor_id GROUP BY a.autor_id ; // Atribut podle kterého se bude seskupovat // Můžeme použít i kniha_autor.autor_id
Seskupení v dotazu Bez použití klauzule GROUP BY by předchozí dotaz dopadl následovně: MySQL našel příjmení Šeďová a Zounek, ale agregační funkce vypočítala jen celkovou hodnotu počtu záznamů odpovídající podmínce. Bez klauzule GROUP BY nelze agregační funkci COUNT použít pro seskupení k určité hodnotě (id autora). Agregační funkce COUNT() bez použití klauzule GROUP BY sečte všechny řádky! Autor Knih Šeďová 3
Seskupení v dotazu Jinou možností by bylo zjištění, kolik má kniha autorů (srovnejte s předchozím dotazem): SELECT k.nazev AS Kniha, COUNT(ka.autor_id) AS Autori FROM knihy AS k, kniha_autor AS ka WHERE k.kniha_id = ka.kniha_id GROUP BY k.kniha_id ; Kniha Autori Učitelé a technologie 2 E-learning 1
GROUP_CONCAT Funkce GROUP_CONCAT funguje podobně jako CONCAT, ale umožňuje spojit hodnoty z různých záznamů do jednoho pole. Příklad: Vzpomeňme dříve uvedený výsledek dotazu spojení (snímek 8): Předložit toto uživateli aplikace by chtělo hodně odvahy . Naštěstí máme k dispozici funkci GROUP_CONCAT, která spojí jména autorů. Kniha Autor Učitelé a technologie Klára Šeďová Jiří Zounek E-learning
GROUP_CONCAT SELECT k.nazev AS Kniha, GROUP_CONCAT(a.prijmeni SEPARATOR ', ' ) AS Autori // SEPARATOR určuje znak oddělení hodnot FROM knihy AS k, autori AS a, kniha_autor AS ka WHERE k.kniha_id = ka.kniha_id AND ka.autor_id = a.autor_id GROUP BY k.kniha_id; Kniha Autori Učitelé a technologie Šeďová, Zounek E-learning Zounek
Klauzule HAVING Příklad: Pomocí HAVING můžeme do dotazů vkládat podmínky s agregačními funkcemi, což za klíčovým výrazem WHERE nelze (jedině pomocí vnořených dotazů). Příklad: Chceme vypsat názvy knih, které mají více než jednoho autora: Řešení: Bude potřeba spojit data s tabulek knihy a kniha_autor. Z tabulky knihy potřebujeme znát název knihy a její identifikátor, pro podmínku spojení s tabulkou kniha_autor. V tabulce kniha_autor potřebujeme vypočítat počty autorů pro jednotlivé knihy a vložit je do podmínky klauzule HAVING.
Řešení SELECT k.nazev FROM knihy AS k, kniha_autor AS ka WHERE k.kniha_d = ka.kniha_id GROUP BY k.kniha_id // Používáme agr. funkci COUNT, proto nesmíme vynechat klauzuli GROUP BY HAVING COUNT( ka.autor_id ) > 1;
Zapamatujte si Čárkové spojení Seskupení v dotazu GROUP BY Podmínky použití GROUP BY CONCAT, GROUP_CONCAT Klauzule HAVING