Databázové systémy II Přednáška č. 9 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Obsah Pokročilé dotazy ve standardu SQL 2 Pseudo-sloupec ROWNUM Klauzule WITH Hierarchické dotazy
Vnořené dotazy Vnořené dotazy (poddotazy) se mohou vyskytovat prakticky na libovolném místě hlavního dotazu. Výsledkem vnořeného dotazu je obecně „virtuálního tabulka“ o několika řádcích a několika sloupcích (v určitých případech pak jednosloupcová či jednořádková) nebo jen jedna jediná hodnota. a) Vnořený dotaz v klauzuli FROM nebo JOIN – s výsledkem poddotazu se pracuje stejně jako při spojení s tabulkou či pohledem, výsledek poddotazu je v tomto případě vhodné označit aliasem b) Vnořený dotaz vracející jednu hodnotu v části WHERE – např. výsledek agregační funkce (SUM, COUNT, MIN, MAX, AVG) se porovnává s hodnotou v určitém sloupci tabulky (nebo je vnořeným dotazem vyhledána hodnota v určitém sloupci, kdy řádek tabulky je identifikován pomocí primárního klíče) c) Použití vnořeného dotazu v části WHERE s využitím množinových operátorů IN, ANY, SOME, ALL
Vnořené dotazy d) Využití výsledků vnořeného dotazu pomocí operací – UNION, INTERSECT, MINUS, … e) Použití vnořeného dotazu v části definice výstupních sloupců dotazu, kde se prostřednictvím vnořeného dotazu doplňují hodnoty na základě ostatních hodnot v daném řádku SELECT (select c1 from t1 b where a.c1 = b.c1), c2 FROM t1 a WHERE
Pseudo-sloupec ROWNUM ROWNUM – magický sloupec, příčinou řady potíží, proto je nezbytné mu porozumět, pak může být velmi užitečný. Lze jej použít: -Pro ladění dotazů, -Pro číslování v rámci dotazu, -pro provádění nejvyšších N- zpracování Sloupci ROWNUM budou přiřazena čísla 1, 2, 3, 4,.. N Hodnota ROWNUM není přiřazena řádku, řádek v tabulce nemá číslo. Hodnota ROWNUM je přiřazena řádku po jeho průchodu fází predikátu dotazu, ale před řazením nebo souhrnem.
Pseudo-sloupec ROWNUM Hodnota ROWNUM je zvýšena pouze po jejím přiřazení, proto následující dotaz nikdy nevrátí žádný řádek SELECT * FROM zamestnanci WHERE ROWNUM<=5 ORDER BY mzda Správný zápis pro omezení počtu řádků: SELECT * FROM (SELECT * FROM zamestnanci ORDER BY mzda) WHERE ROWNUM<=5 Správný zápis pro uvedení rozsahu řádků: SELECT * FROM (SELECT dotaz.*, ROWNUM as radek FROM (SELECT * FROM trpaslici ORDER BY jmeno) dotaz) WHERE radek BETWEEN 3 and 5; Použití sloupce ROWNUM nahrazuje klauzuli LIMIT známou z MySQL pro určení rozsahu řádků na výstupu.
Náhrada ROWNUM Alternativně je možné použít analytické funkce ROW_NUMBER() SELECT * FROM (SELECT jmeno, ROW_NUMBER() OVER (ORDER BY jmeno) as radek FROM trpaslici) WHERE radek BETWEEN 3 and 5
Příkazy s klauzulí WITH Klauzule WITH umožňuje přiřadit název určitému poddotazu uvedenému před vlastním dotazem SELECT. V něm se pak můžete odkazovat na tento poddotaz zadáním jména poddotazu – obdobně jako při práci s pohledy. Oracle optimalizuje zpracování poddotazu uvedeného jména - buď jako inline pohled nebo jako dočasnou tabulku. Jednotlivé poddotazy se mohou odkazovat na předchozí poddotazy, stejně jako se na ně odkazuje hlavní dotaz. Použití klauzule WITH je velice vhodné v případě, kdy je výsledek poddotazu odkazován vícekrát v rámci jediného dotazu, například, když průměrné hodnoty zjištěné poddotazem musí být několikrát porovnávány během vykonávání dotazu a běžné řešení by znamenalo bud zřízení samostatného pohledu nebo uvedení několika totožných vnořených dotazů v rámci hlavního dotazu. Architektury a techniky DS – cv. 1 8
Příkazy s klauzulí WITH - příklad WITH AS (subquery_sql_statement) SELECT FROM ; Příklad: select store_name, sum(quantity) store_sales, (select sum(quantity) from sales)/(select count(*) from store) avg_sales from store s, sales sl where s.store_key = sl.store_key having sum(quantity) > (select sum(quantity) from sales)/(select count(*) from store) group by store_name Architektury a techniky DS – cv. 1 9
Příkazy s klauzulemi WITH - příklad WITH sum_sales AS select sum(quantity) all_sales from stores, number_stores AS select count(*) nbr_stores from stores, sales_by_store AS select store_name, sum(quantity) store_sales from store natural join sales SELECT store_name FROM store, sum_sales, number_stores, sales_by_store WHERE store_sales > (all_sales / nbr_stores); Architektury a techniky DS – cv. 1 10
Syntaxe průchodu stromů v Oracle 9i,10 SELECT sloupce FROM tabulka [WHERE podmínka3] START WITH podmínka1 CONNECT BY podmínka2 [ORDER BY …] Řádky vyhovující podmínce ve START WITH jsou považovány za kořenové řádky na první úrovni vnoření Pro každou řádku na úrovni i se rekurzivně hledají přímí potomci vyhovující podmínce v klauzuli CONNECT BY na úrovni i+1 Řádka předka se v podmínce označuje klíčovým slovem PRIOR Na závěr jsou odstraněny řádky nevyhovující podmínce ve WHERE Pokud není definováno třídění, odpovídá pořadí průchodu pre-order Každý řádek obsahuje pseudo-sloupec LEVEL, obsahující úroveň řádku v hierarchii Architektury a techniky DS – cv. 1 11
Příklad hierarchického dotazu Příklad: SELECT PRIJMENI, JMENO, level -- pseudosloupec označující úroveň FROM A_HR.ZAMESTNANCI CONNECT BY MANAZER_ID = PRIOR ZAMESTNANEC_ID -- MANAZER_ID se rovná ZAMESTNANEC_ID u předchůdce START WITH MANAZER_ID is null; -- začni od zaměstnance, který nemá nadřízeného Architektury a techniky DS – cv. 1 12
Doplnění hierarchických dotazů Pro jednotlivé záznamy můžete také získat cestu od nejvyššího záznamu (jak to znáte třeba ze souborového systému) nebo řadu dalších informací: Funkce SYS_CONNECT_BY_PATH vrací cestu v hierarchii k aktuálnímu záznamu. Klauzule CONNECT_BY_ROOT vrací hodnotu z příslušného záznamu nejvyšší úrovně (tj. například nejvyššího manažera). Pokud byste chtěli výstup z dotazu použít pro zobrazení ve formě rozbalovací hierarchie tak, jak to třeba dělá u souborů Windows Explorer, bude se vám hodit i pseudosloupec CONNECT_BY_ISLEAF, který určuje, zda je aktuální záznam na poslední úrovni hierarchie (CONNECT_BY_ISLEAF=1) nebo zda má podřízené záznamy (CONNECT_BY_ISLEAF=0). Architektury a techniky DS – cv. 1 13
Příklad hierarchických dotazů SELECT lpad(' ',level*3)||PRIJMENI||' '||JMENO name, SYS_CONNECT_BY_PATH(PRIJMENI, '/') path, CONNECT_BY_ROOT PRIJMENI topmgr, CONNECT_BY_ISLEAF isleaf, level FROM A_HR.ZAMESTNANCI CONNECT BY MANAZER_ID = PRIOR ZAMESTNANEC_ID START WITH MANAZER_ID is null ORDER SIBLINGS BY PRIJMENI; NAMEPATHTOPMGRISLEAFLEVEL King Steven/KingKing01 Cambrault Gerald/King/CambraultKing02 Bates Elizabeth/King/Cambrault/BatesKing13 Bloom Harrison/King/Cambrault/BloomKing13 Fox Tayler/King/Cambrault/FoxKing13 Kumar Sundita/King/Cambrault/KumarKing13 Ozer Lisa/King/Cambrault/OzerKing13 Smith William/King/Cambrault/SmithKing13 De Haan Lex/King/De HaanKing02 Hunold Alexander/King/De Haan/HunoldKing03 Austin David/King/De Haan/Hunold/AustinKing14 Architektury a techniky DS – cv. 1 14
Hierarchické dotazy dle ANSI SQL Hierarchické dotazy dle ANSI SQL používají rekurzívní WITH klauzuli, která se odkazuje sama na sebe. Zavedení této syntaxe do Oracle 11gR2 zajišťuje hierarchickým dotazům Oracle SQL kompatibilitu s ANSI. Architektury a techniky DS – cv. 1 15
Hierarchické dotazy dle ANSI SQL with employees (empno, name, job, mgr, hierlevel) as ( select empno, ename, job, mgr, 1 from emp where mgr is null union all select e.empno, e.ename, e.job, e.mgr, m.hierlevel + 1 from emp e join employees m on (m.empno = e.mgr) -- podmínka spojení a rekurzívní volání ) select * from employees Viz např. end-of-hierarchical-querying-as-we-know-ithttp://technology.amis.nl/blog/6104/oracle-rdbms-11gr2-goodbye-connect-by-or-the- end-of-hierarchical-querying-as-we-know-it Architektury a techniky DS – cv. 1 16
Hierarchické dotazy dle ANSI SQL with org_pracovniku (ZAMESTNANEC_ID, PRIJMENI, JMENO, MANAZER_ID, uroven) as ( select ZAMESTNANEC_ID, PRIJMENI, JMENO, MANAZER_ID, 1 from A_HR.ZAMESTNANCI where MANAZER_ID is null-- začni od zaměstnance, který nemá nadřízeného union all-- spoj výsledek předchozího dotazu s výsledkem následujícího dotazu select pracovnici.ZAMESTNANEC_ID, pracovnici.PRIJMENI, pracovnici.JMENO, pracovnici.MANAZER_ID, manazeri.uroven+ 1 from A_HR.ZAMESTNANCI pracovnici join org_pracovniku manazeri on (manazeri.ZAMESTNANEC_ID = pracovnici.MANAZER_ID) -- podmínka spojení a rekurzívní volání ) select * from org_pracovniku Viz např. Architektury a techniky DS – cv. 1 17