3. CVIČENÍ |
Hierarchické dotazy :
Nyní navážeme na poslední dotaz z předchozího cvičení:
SELECT a.prijmeni, a.jmeno, b.prijmeni, b.jmeno FROM osoby a, osoby b WHERE a.id_nad = b.id_osoby;Výše uvedený dotaz vlastně zobrazí vždy dvě úrovně z celé hierarchie osob. Tímto způsobem lze zobrazit i např. první tři horní úrovně hierarchie "trojnásobným spojením", kořen stromu (nejvýše postavená osoba) má ID_NAD rovno NULL. Tatkto lze ale provádět dotazy vždy jen s pevným počtem úrovní v hierarchii osob (kolikrát je proveden self-join). V závislosti na datech se však počet úrovní může dynamicky měnit. RDBMS Oracle umožňuje procházet stromovou hierarchii do hloubky pomocí SQL klauzule CONNECT BY PRIOR. Pseudo-sloupec LEVEL udává v jaké úrovni se právě nacházíme. Následující dotaz projde pro každou osobu i všechny její podřízené. Vazba rodič - potomek je definována podmínkou v klauzuli CONNECT BY PRIOR, kde PRIOR označuje stranu rodiče. Pozor, tuto konstrukci podporuje POUZE Oracle.
SELECT LEVEL, jmeno, prijmeni FROM osoby CONNECT BY PRIOR id_osoby = id_nad;Způsob procházení hierarchie ukazuje spodní obrázek:
Seznam osob s jejich nařízenými:
SELECT LEVEL, jmeno, prijmeni FROM osoby CONNECT BY id_osoby = PRIOR id_nad;Výše uvedené dotazy prochází strukturu rekurzivně pro každý záznam. Můžeme však specifikovat, odkud se má začít hierarchická struktura prohledávat:
SELECT LEVEL, jmeno, prijmeni FROM osoby CONNECT BY PRIOR id_osoby = id_nad START WITH id_nad IS NULL;Takto přehledně zobrazíme celou hierarchii:
SELECT LPAD(' ', (LEVEL-1)*8)||jmeno||' '||prijmeni AS osoba
FROM osoby
CONNECT BY PRIOR id_osoby = id_nad
START WITH id_nad IS NULL;
Zobrazení hierarchie od určité osoby:
SELECT LPAD(' ', (LEVEL-1)*8)||jmeno||' '||prijmeni AS osoba
FROM osoby
CONNECT BY PRIOR id_osoby = id_nad
START WITH jmeno = 'Karel' AND prijmeni = 'Vavricka';
Zobrazení cesty od libovolného zaměstance až ke generálnímu řediteli:
SELECT LPAD(' ', (LEVEL-1)*8)||jmeno||' '||prijmeni AS osoba
FROM osoby
CONNECT BY id_osoby = PRIOR id_nad
START WITH id_nad IS NOT NULL;
Zobrazení cesty od konkrétního zaměstance až ke generálnímu řediteli:
SELECT LPAD(' ', (LEVEL-1)*8)||jmeno||' '||prijmeni AS osoba
FROM osoby
CONNECT BY id_osoby = PRIOR id_nad
START WITH jmeno = 'Maxmilian' AND prijmeni = 'Rohlik';
Zobrazení úrovně, na které se v hierarchii nachází daný zaměstnanec:
SELECT MAX(LEVEL) FROM osoby CONNECT BY PRIOR id_osoby = id_nad START WITH prijmeni = 'Vavricka';Počet podřízených (i nepřímých) daného zaměstnance:
SELECT COUNT(*) - 1 AS pocet FROM osoby CONNECT BY PRIOR id_osoby = id_nad START WITH prijmeni = 'Dudacek';Počet podřízených (i nepřímých) všech zaměstnanců:
SELECT jmeno, prijmeni, COUNT(*) - 1 AS pocet
FROM osoby
CONNECT BY id_osoby = PRIOR id_nad
GROUP BY jmeno, prijmeni
ORDER BY 3 DESC;
Sjednocení a průnik dotazů :
SELECT p1.zkratka, r1.semestr, r1.den, r1.h_od, r1.h_do, m1.zkratka
FROM predmety p1, rozvrh r1, mistnosti m1
WHERE p1.id = r1.id_predm
AND r1.id_mistn = m1.id
UNION
SELECT p2.zkratka, '*', '*', -1, -1, '*'
FROM predmety p2
WHERE NOT EXISTS ( SELECT *
FROM rozvrh r2
WHERE p2.id = r2.id_predm );
Pozn.: dotazy musí vracet stejný počet sloupců a typy jednotlivých
sloupců si musí odpovídat.
Sjednocení odstraňuje duplicitní záznamy :
SELECT p1.zkratka, r1.semestr
FROM predmety p1, rozvrh r1, mistnosti m1
WHERE p1.id = r1.id_predm
AND r1.id_mistn = m1.id
UNION
SELECT p2.zkratka, '*'
FROM predmety p2
WHERE NOT EXISTS ( SELECT *
FROM rozvrh r2
WHERE p2.id = r2.id_predm );
Nepřejeme-li si duplicitní záznamy odstranit, musíme použít pro
sjednocení klauzuli UNION ALL :
SELECT p1.zkratka, r1.semestr
FROM predmety p1, rozvrh r1, mistnosti m1
WHERE p1.id = r1.id_predm
AND r1.id_mistn = m1.id
UNION ALL
SELECT p2.zkratka, '*'
FROM predmety p2
WHERE NOT EXISTS ( SELECT *
FROM rozvrh r2
WHERE p2.id = r2.id_predm );
Průnik dotazů realizujeme pomocí klíčového slova INTERSECT :
SELECT p1.zkratka, r1.semestr, r1.den FROM predmety p1, rozvrh r1, mistnosti m1 WHERE p1.id = r1.id_predm AND r1.id_mistn = m1.id AND r1.semestr = 'LS' INTERSECT SELECT p1.zkratka, r1.semestr, r1.den FROM predmety p1, rozvrh r1, mistnosti m1 WHERE p1.id = r1.id_predm AND r1.id_mistn = m1.id AND r1.den = 'PO';
Zjistěte strukturu jednotlivých tabulek v databázi a na základě této informace a znalosti E-R modelu napište dotazy v SQL, které zobrazí :