SQL Další dotazy a pohledy Databázové systémy
Některé SQL příkazy mohou mít v sobě obsaženy další kompletní příkazy SELECT. Využijeme je tam, kde potřebujeme nejprve zjistit nějakou informaci a v závislosti na ní pak informace další. Mohou se vyskytovat v klauzulích WHERE a HAVING vnějšího příkazu SELECT - také v příkazech INSERT,UPDATE,DELETE. Vnořený dotaz je vždy uzavřen mezi závorkami. Vnořený dotaz je ve výrazu vždy na pravé straně. Vnořený dotaz musí vracet vždy pouze jeden sloupec (výraz). V případě, že používáme srovnávací operátory, musí vnořený dotaz vracet právě jeden řádek. Výjimkou jsou množinové operátory. Vnořené dotazy
Příklad: Vypište seznam všech studentů, kteří mají nadprůměrný studijní průměr. Pomocí jednoduchých SQL dotazů, tento výsledek obdržíme ve dvou krocích. Nejprve si zjistíme, jaký je průměrný studijní průměr (použijeme agregační funkci AVG): Vnořené dotazy SELECT AVG(st_prumer) FROM student; Tento dotaz nám vrátí např. číslo Toto číslo si zapamatujeme a použijeme jej v konstrukci následujícího dotazu: SELECT jmeno, prijmeni FROM student WHERE st_prumer > 1.95;
Za jednoduchý vnořený dotaz budeme považovat vnořený příkaz SELECT vracející nám jednu hodnotu. Jednoduché vnořené dotazy SELECT jmeno, prijmeni FROM student WHERE st_prumer> (SELECT AVG(st_prumer) FROM student); Vnořeným SELECT-em se nám vyhodnotí Vypočtená_hodnota na jednu hodnotu a máme tedy podmínku zapsanou v pořádku. Vnořený SELECT se vyhodnotí pouze jednou, hodnotu si SQL server "zapamatuje" a s ní pak porovnává všechny ostatní hodnoty v tabulce. V jednoduchých vnořených dotazech – poddotazech, budou obdobným způsobem fungovat i další agregační funkce.
Operátory - IN, ANY (SOME), ALL Vnořování dotazů nám rozšiřuje klasickou množinu relačních operátorů o operátory další, které se aplikují z levé strany na sloupec a z pravé strany na vnořený dotaz vracející více hodnot. IN - slouží pro jednoduché porovnání, zdali se hodnota sloupce vlevo vyskytuje mezi hodnotami vrácenými vnořeným dotazem. Kdybychom např. chtěli jména a příjmení studentů, kteří nastoupili do školy v letech 2000 až 2003, mohli bychom takový dotaz pomocí operátoru IN zapsat takto: Poddotazy vracející více hodnot SELECT jmeno,prijmeni,datum_zapisu FROM student WHERE YEAR(datum_zapisu) IN (2000,2001,2002,2003);
ANY (nebo SOME) - určují, že relace se vztahuje na alespoň jednu z hodnot, kterou vrátí vnořený dotaz. Chceme-li seznam předmětů, které vyučuje libovolný učitel z Katedry informatiky: Poddotazy vracející více hodnot SELECT nazev,id_uc FROM predmet WHERE id_uc = ANY (SELECT id_uc FROM ucitel WHERE katedra ="KI") Je to možné zapsat taky: SELECT nazev,id_uc FROM predmet WHERE id_uc IN(SELECT id_uc FROM ucitel WHERE katedra ="KI") To znamená, že je totožné použití IN a = ANY.
ALL - aplikuje relaci na všechny hodnoty vrácené poddotazem. Chceme-li seznam předmětů, které vyučuje libovolný učitel, který není z Katedry informatiky: Poddotazy vracející více hodnot SELECT nazev,id_uc FROM predmet WHERE id_uc <>ALL (SELECT id_uc FROM ucitel WHERE katedra ="KI") SELECT nazev,id_uc FROM predmet WHERE id_uc NOT IN (SELECT id_uc FROM ucitel WHERE katedra ="KI") nebo V tomto případě platí, že je totožné NOT IN a <> ALL.
Tento operátor vrací pravdivostní hodnotu TRUE nebo FALSE na základě toho, zda vnořený SQL dotaz vrací nějakou hodnotu. EXISTS ( vnořený SQL dotaz ); Jestli vnořený SQL dotaz vrátí alespoň jeden řádek, operátor EXISTS nám vrátí TRUE. Poznámka: Vnořený SQL dotaz v argumentu operátoru EXISTS se vyhodnocuje zvlášť pro každý řádek. Chceme zkontrolovat, zdali u každého studenta jsou zadané předměty, na které se zapsal. Chceme tedy seznam studentů, u kterých nemáme v systému zadaný žádný předmět: Operátor EXISTS SELECT jmeno,prijmeni FROM student WHERE NOT EXISTS(SELECT id_st FROM zapis WHERE student.id_st=zapis.id_st);
Pro sjednocení výsledků dotazů slouží klíčové slovo UNION, za kterým následuje další příkaz SELECT. Chceme seznam všech předmětů, které navštěvuje Anna Antalová, nebo Bruno Babel. a) bez použití skládání dotazů: Skládání dotazů - Sjednocení dotazů SELECT distinct p.nazev FROM student s, zapis z, predmet p WHERE s.id_st = z.id_st AND z.id_pr = p.id_pr AND ( (jmeno = 'Anna' AND prijmeni = 'Antalova') OR (jmeno = 'Bruno' AND prijmeni = 'Babel'));
SELECT p.nazev FROM student s, zapis z, predmet p WHERE s.id_st = z.id_st AND z.id_pr = p.id_pr AND jmeno = 'Anna' AND prijmeni = 'Antalova' UNION SELECT p.nazev FROM student s, zapis z, predmet p WHERE s.id_st = z.id_st AND z.id_pr = p.id_pr AND jmeno = 'Bruno' AND prijmeni = 'Babel'; Skládání dotazů - Sjednocení dotazů b) s pomocí sjednocení :
Pro průnik se používá klíčové slovo INTERSECT. Chceme názvy všech předmětů, které navštěvuje Anna Antalová a zároveň Bruno Babel (a možná někdo další, ale to už nás nezajímá). a) bez použití průniku dotazů: Skládání dotazů - Průnik dotazů SELECT distinct p.nazev FROM student s, je_zapsan jz, predmet p WHERE s.id_st = jz.id_st AND jz.id_pr = p.id_pr AND ( (jmeno = 'Anna' AND prijmeni = 'Antalova') AND (jmeno = 'Bruno' AND prijmeni = 'Babel')); Takový dotaz je samozřejmě chybný. V žádném řádku pseudotabulky, která vznikne spojením uvedených tří tabulek, nemůže nastat situace, že by jméno bylo Anna a zároveň Bruno.
SELECT p.nazev FROM student s, zapis z, predmet p WHERE s.id_st = z.id_st AND z.id_pr = p.id_pr AND jmeno = 'Anna' AND prijmeni = 'Antalova' INTERSECT SELECT p.nazev FROM student s, zapis z, predmet p WHERE s.id_st = z.id_st AND z.id_pr = p.id_pr AND jmeno = 'Bruno' AND prijmeni = 'Babel'; Skládání dotazů - Průnik dotazů ) s použitím průniku dotazů :
Další příkazy SQL uzamkne jmenované tabulky pro čtení (READ), nebo zápis (WRITE) - po uzamknutí mají právo čtení, nebo zápisu v tabulce pouze ty příkazy, které se nachází mezi LOCK... UNLOCK. UNLOCK TABLES; - odemčení všech zamčených tabulek. Vytvoření dočasné tabulky LOCK TABLES nazev_tabulky READ, nazev_tabulky WRITE; CREATE TEMPORARY TABLE nazev_tabulky (nazev_sloupce datovy_typ,.. ); - takto vytvoříme dočasnou, která po uzavření spojení s databází zanikne. Uzamčení tabulky
Výstup do textového souboru: TO OUTFILE SELECT * FROM Tabulka INTO OUTFILE „Soubor“; Načtení dat z textového souboru: LOAD DATA INFILE Provede načtení řádků z textového souboru do tabulky, velkou rychlostí. Provede výpis výsledku do textového souboru "Soubor". Název souboru musí být textový řetězec (v uvozovkách). Prioritně se načte do aktivní databáze, ale lze zadefinovat i jinou databázi - databaze.tabulka; LOAD DATA INFILE 'data.txt' INTO TABLE tabulka;
Uživatelské proměnné - do proměnné "a" se uloží nějaká "hodnota", kterou si MySQL pamatuje do konce aktuálního spojení - (proměnnou nelze zatím použít úplně ve všech dotazech MySQL). - platí pro sloupce typu CHAR, VARCHAR a TEXT - fultextový index slouží k rychlejšímu hledání dat v textových polích -hledání v takovýchto polích provádíme pomocí příkazů -MATCH a AGAINST. př.: Index FULLTEXT SELECT * FROM tabulka WHERE MATCH(sloupec) AGAINST("hledana_hodnota");
Pohledy Z bázových tabulek odvozené virtuální tabulky. CREATE VIEW jm_pohledu [(jm_sloupce, …)] AS tab_výraz [WITH CHECK OPTION] Vytvoření pohledu - uloží definici pohledu do systémového katalogu Sloupce musí mít jednoznačná jména. Př) Pohled pro klienty z pobočky Zarámí. CREATE VIEW Zarami AS SELECT K.* FROM Klient K, Ucet U WHERE K.r_cislo=U.r_cislo AND U.pobocka=‚Zarámí' WITH CHECK OPTION WITH CHECK OPTION - kontrola, že při změně nedochází k porušení def. pohledu.
DROP VIEW jm_pohledu [RESTRICT|CASCADE]; Odstranění pohledu - Zruší informaci o pohledu ze systémového katalogu Př) SELECT * FROM Zarami WHERE mesto=´Zlín´; b SELECT K.* FROM Klient K, Ucet U WHERE K.mesto=´Zlín´ AND K.r_cislo=U.r_cislo AND U.pobocka=‚Zarámí' Manipulace na pohledech SŘBD musí být schopen jednoznačně transformovat operace řádku pohledu na operace nad zdrojovými bázovými tabulkami pohledu.
CREATE VIEW pocty (nazev,pocet) AS SELECT pobocka, COUNT(*) FROM Ucet GROUP BY pobocka; Pohledy s klauzulemi DISTINCT, GROUP BY, HAVING, s agregačními funkcemi a spojující několik tabulek umožňují jen čtení. Selektivní pohled CREATE VIEW Zlinsti AS SELECT * FROM Klient WHERE mesto=´Zlín´; Agregační pohled CREATE VIEW Pocty (nazev,počet) AS SELECT pobocka,COUNT(*) FROM Ucet GROUP BY pobocka;
Projektivní pohled bez PK CREATE VIEW Zlinsti1 AS SELECT ulice FROM Klient WHERE mesto=´Zlín´; INSERT INTO Zlinsti1 VALUES (´Štefánikova 4562´); Projektivní pohled s PK CREATE VIEW Zlinsti2 AS SELECT r_cislo,ulice FROM Klient WHERE mesto=´Zlín´; INSERT INTO Zlinsti2 VALUES (´561212/1254´,´Štefánikova 4562´);
Materializované pohledy Pohledy, u nichž je výsledek dotazu definujícího pohled skutečně fyzicky uložen v databázi a je zajištěna aktualizace obsahu. Důvod: Zvýšení efektivnosti, resp. omezený přístup k datům. Hlavní oblasti použití: Datové sklady – sumarizační pohledy. Distribuované databáze – replikace dat v uzlech. Mobilní databáze – materializace pohledů používaných mobilními klienty.
Materializované pohledy Pohledy, u nichž je výsledek dotazu definujícího pohled skutečně fyzicky uložen v databázi a je zajištěna aktualizace obsahu. Důvod: Zvýšení efektivnosti, resp. omezený přístup k datům. Hlavní oblasti použití: Datové sklady – sumarizační pohledy. Distribuované databáze – replikace dat v uzlech. Mobilní databáze – materializace pohledů používaných mobilními klienty.