620 likes | 805 Views
1.12.2004. Rekurzívne dotazy. Juraj Fečanin Aleš Plšek. C íle. 1.cíl Jak funguje rekurze v SQL? 2.cíl Zásady implementace. Obsah. Úvod Konstrukce a průběh rekurzivních dotazů Logické hierarchie a jejich vztah k rekurzi Zastavení rekurzivního výpočtu
E N D
1.12.2004 Rekurzívne dotazy Juraj Fečanin Aleš Plšek
Cíle 1.cíl Jak funguje rekurze v SQL? 2.cíl Zásady implementace
Obsah • Úvod • Konstrukce a průběh rekurzivních dotazů • Logické hierarchie a jejich vztah k rekurzi • Zastavení rekurzivního výpočtu • Příklady, pokročilejší techniky rekurze • Zásady implementace • Závěr
I. kapitola Úvod
Úvod • SQL příkaz – správnost výsledku, čitelnost a efektivnost • Rekurzivní SQL příkaz čitelnost a srozumitelnost • Proč tedy používat rekurzivní dotazy? • Někdy jediný efektivní způsob získání výsledku
Použití • Efektivní řešení problému na komplexních strukturách dat. • Vhodné při dotazech, kdy každý zpracovaný záznam bude součástí výsledku (Najdi všechny zaměstnance pracující pro Boba.) • Nebezpečné pro dotazy s nízkým počtem záznamů v odpovědi (Najdi pět nejrychlejších spojů z Bostonu do Dallasu.)
Další informace • Základní pravidlo: Vyloučit co největší počet záznamů jak nejrychleji to je možné • Vede ke snížení čitelnosti • Pozor u zacyklených dat! • Problémy s rekurzivními SQL příkazy • Při dodržení správných zásad mohou být efektivním a užitečným nástrojem
K čemu se rekurze používá? • Vytvoření náhodného vzorku dat (Sample data) • Výpis prvních n záznamů • Generování jednoduchých parserů • Zjištení hierchických vazeb mezi záznamy • Normalizace a denormalizace datových struktur
II. kapitola Konštrukcia a priebeh rekuzívnych dotazov
Rekurzia v SQL • Výraz je rekurzívny, ak používa sám seba v svojej definícii • Náhrada programu, ktorý by spracovával výsledky dotazov • Nebezpečenstvo zacyklenia
Nerekurzívne dotazy 1 • Tabuľka, na ktorej si vysvetlíme základné princípy rekurzívnych dotazov
Nerekuzívne dotazy 2 • Mená zamestnancov, ktorých nadriadený je pán Hoover a zarábajú viac ako $100.000 • Čo ak chceme vypísať mená všetkých Hooverových podriadených (nielen priamo), ktorí zarábajú viac ako $100.000
Pravidlá pre rekurzívne dotazy 1 • Definujeme výraz s použitím klauzule WITH • na jeho základe sa vytvorí dočasný pohľad • tento výraz musí byť definovaný ako zjednotenie dvoch oddelených častí (UNION ALL) • prvá časť - inicializačný poddotaz - bez rekurzie - vyhodnocovaný ako prvý • druhá časť - rekurzívny poddotaz - pridáva nové riadky do dočasného pohľadu - pozor na zarážku
Pravidlá pre rekurzívne dotazy 2 • Rekurzívny poddotaz • nemá obsahovať stĺpcové funkcie, SELECT DICTINCT, GROUP BY alebo HAVING • má obsahovať odkaz na výraz, v ktorom je zahrnutý sám, ale nie poddotaz nižšej úrovne • každý stĺpec rekurzívneho poddotazu musí byť kompatibilný s príslušným stĺpcom inicializačného poddotazu(cast)
Pravidlá pre rekurzívne dotazy 3 • Za klauzulou WITH musí byť definovaný dočasný pohľad
WITH adepti(meno,plat) AS ((SELECT meno,plat[inicializačný poddotaz] FROM zamestnanci WHERE nadriadeny=‘Hoover’) UNION ALL (SELECT z.meno,z.plat [rekurzívny poddotaz] FROM adepti AS a,zamestnanci AS z WHERE z.nadriadeny=a.meno)) SELECT meno[finálny dotaz] FROM adepti WHERE plat>100000; Príklad
Príklad - komentár • pri vyhodnocovaní dočasného pohľadu, databáza vidí iba riadky, ktoré boli pridané v predchádzajúcej iterácii • systém pokračuje v rekurzii, kým sa do pohľadu pridávajú riadky • potreba byť opatrný – nekonečný cyklus
Odlišný pohled • Dočasná tabulka jako fronta záznamů • Na začátku obsahuje záznamy získané z inicializačního dotazu • Postupně na každý záznam spušten iterační dotaz, výsledky se přidávají na začátek fronty • Proces končí při vyprázdnění fronty
Odlišný pohled - ilustrace AAA BBB CCC DDD EEE FFF GGG
Odlišný pohled - poznámky • Výstup rekurzivního dotazu může být použit v dalším rekurzivním výrazu (Najdi všechny státy v USA a pak všechny města v každém státě.) • Pozor u UNION ALL, nestačí jen UNION (s ohledem na duplicity) • Pro efektivnější zpracování dotazu se doporučuje vhodná indexace záznamů • Výstupem je dočasná tabulka – zachována platnost všech definovaných omezení pro dočasné tabulky
Možnosti použitia • ak je rekurzívny dotaz použitý vo vnútri výrazu CREATE VIEW, definuje sa rekurzívny pohľad • ak vo vnútri INSERT výrazu, je jeho výsledok vložený do cieľovej tabuľky • veľmi silná technika • napr. chceme vytvoriť tabuľku ČÍSLA so stĺpcami PORADOVÉ a NÁHODNÉ čísla od 1 do 1000 náhodné čísla od 1 do 1000
Príklad CREATE TABLE čísla(poradové Integer,náhodné Integer); INSERT INTO čísla(poradové,náhodné) WITH dočasné(n) AS (VALUES(1) [inicializačný poddotaz] UNION ALL SELECT n+1 FROM dočasné [rekurzívny poddotaz] WHERE n<1000) SELECT n,integer(rand()*1000) FROM dočasné;
III. kapitola Logické hierarchie a jejich vztah k rekurzi
Logické hierarchie • Logické hierarchie v reálném světě a jejich reprezentace v relačních databázích • Typy hierarchií • Divergentní • Konvergentní • Rekurzivní • Další rozeznávaná vlastnost • Vyvážená/Nevyvážená
Divergentní hierarchie AAA BBB CCC DDD EEE FFF GGG • Žádný objekt nemá více než jednoho předka • Libovolný počet potomků • Často obsahuje každá vrstva vždy jen jeden typ objektů • Např. geografická hierarchie = země,kraj,město,ulice • Implementace - stačí jedna tabulka
Konvergentí hierarchie • Libovolný počet předků a potomků • Reprezentují např. logické objekty, výrobky(popis součástek) • Implementace – dvě tabulky • Tabulka popisující objekty • Tabulka popisující vztahy mezi objekty AAA BBB CCC DDD EEE FFF GGG
Konvergentí hierarchie - příklad Objekty Vztahy AAA BBB CCC DDD EEE FFF GGG
Rekurzivníhierarchie • Libovolný počet předků • Objekt může být přímo či nepřímo svým předkem • V reálném světě je tato hierarchie téměř vždy špatná • Většinou nahrazuje konvergentní hierarchii tam, kde to přispěje ke zjednodušení • Realizace - jako u konvergentní hierarchie AAA BBB CCC DDD EEE FFF GGG
Rekurzivníhierarchie - příklad Objekty Vztahy AAA BBB CCC DDD EEE FFF GGG
Vyvážené/Nevyvážené hierarchie • Vyvážené hierarchie • úroveň = jednotná množina hodnot, stejná vzdálenost objektů od kořene • Většinou každá úroveň obsahuje jiné typy objektů (např. stát, město, ulice) • Nevyvážené hierarchie • Všechny objekty jednotného typu (např. společnost vlastnící další společnosti)
Datové/Ukazatelové hierarchie • Stejný design, různé použití • Ukazatelová hierarchie • V hlavních tabulkách uloženy jen data • Logické struktury a hierarchie definovány zvlášť • Použití např. v bankovních aplikacích
Datové hierarchie • Databáze popisuje vztahy mezi objekty (tabulky obsahující informace o všech součástech letadla) • Při rekurzivním zpracování je třeba být velmi opatrný (např. pro spočítání váhy objektů potřebujeme uvažovat jak počet podobjektů, tak jejich hmotnosti)
IV. kapitola Zastavení rekurzivního výpočtu
Zastavení rekurzivního výpočtu • Jak zjistit, kdy se má výpočet ukončit? • Prevence zacyklení • Techniky zastavení výpočtu: • Skončit po průchodu určitého počtu úrovní • Nevracet se na už jednou navštívená místa
Rekurzivní data • Uvažujme strukturu dat AAA BBB CCC DDD EEE FFF GGG
Zastavení po průchodu n úrovněmi WITH Parent(ckey,lvl) AS ( (SELECT DISTINCT pkey, 0 FROM TROUBLE WHERE pkey = ‘AAA’) UNION ALL (SELECT C.ckey,P.lvl + 1 FROM Trouble C, Parent P WHERE P.ckey = c.pkey AND P.lvl +1 < 4 ) ) SELECT ckey, lvl FROM Parent;
Stop na n-té úrovní, výpis cest WITH Parent(ckey,lvl,path,loc) AS ((SELECT DISTINCT pkey, 0 , VARCHAR (pkey,20) , 0 FROM TROUBLE WHERE pkey = ‘AAA’) UNION ALL (SELECT C.ckey,P.lvl + 1 ,P.path|| ’>’ ||C.ckey , LOCATE (C.ckey|| ’>’ ||P.path) FROM Trouble C , Parent P WHERE P.ckey = c.pkey AND P.lvl +1 < 4 )) SELECT ckey, lvl, path, loc FROM Parent;
Najdi všechny potomky WITH Parent(ckey,lvl,path,loc) AS ( ( SELECT DISTINCT pkey, 0 , VARCHAR (pkey,20) FROM TROUBLE WHERE pkey = ‘AAA’) UNION ALL ( SELECT C.ckey,P.lvl + 1 , P.path|| ’>’ ||C.ckey FROM Trouble C , Parent P WHERE P.ckey = c.pkey AND LOCATE (C.ckey|| ’>’ ||P.path) = 0 ) ) SELECT ckey, lvl, path FROM Parent;
Zastavení při nalezení cyklu WITH Parent(ckey,lvl,path) AS ( ( SELECT DISTINCT pkey, 0 , VARCHAR (pkey,20) FROM TROUBLE WHERE pkey = ‘AAA’) UNION ALL ( SELECTCASE WHENLOCATE (C.ckey||’>’, P.path) > 0 THEN RAISE_ERROR(‘70001’,’Error: Loop in database found’) ELSE C.CKEY END ,P.lvl + 1 , P.path|| ’>’ ||C.ckey FROM Trouble C , Parent P WHERE P.ckey = c.pkey ) SELECT ckey, lvl, path FROM Parent; )
V. kapitola Príklady Problém priechodu častí, Rekurzívne vyhledávánie, CAST výraz,…
Problém priechodu častí 1 • výroba lietadiel • tabuľka všetkých častí, použitých v istom type lietadla, a ich komponent krídlo 1 5 1 výstuha kormidlo podvoz. 100 2 5 3 10 8 čáp 4 nit Orientovaný acyklický graf
Problém priechodu častí 2 Aký je počet nitov použitých na jednom krídle? • problém: Musíme uvažovať aj počet častí obsahujúcich nity. • použijeme tie isté pravidlá ako v predchádzajúcich príkladoch • dočasný pohľad: ČASTI_KRÍDLA • riadok obsahuje komponentu a počet komponent pre istú časť krídla • inicializačný poddotaz vyberie časti, použité priamo pri kompletizovaní krídla • rekurzívny poddotaz vyberá časti na nižších úrovniach kompletizácie • acyklický graf rekurzia sa zastaví
Realizácia WITH časti_krídla(komponenta,počet) AS ((SELECT komponenta,počet [inicializačný poddotaz] FROM komponenty WHERE časť=‘krídlo’) UNION ALL (SELECT k.komponenta,č.počet*k.počet [rekurzívny poddotaz] FROM časti_krídla č,komponenty k WHERE č.komponenta=k.časť)) SELECT sum(počet) AS počet FROM časti_krídla WHERE komponenta=‘nit’; Výsledok:
Realizácia 2 WITH časti_krídla(komponenta,počet) AS ((SELECT komponenta,počet FROM komponenty WHERE časť=‘krídlo’) UNION ALL (SELECT k.komponenta,č.počet*k.počet FROM časti_krídla č,komponenty k WHERE č.komponenta=k.časť)) SELECT komponenta,sum(počet) AS počet FROM časti_krídla GROUP BY komponenta; Výsledok:
Rekurzívne vyhľadávanie Nájdi najlacnejšiu trasu zo San Fracisca do New Yorku. POZOR!!! Graf nie je acyklický. Letová mapa 275 Chicago 250 San Francisco New York 300 50 100 225 Los Angeles Dallas 200
San Francisco – New York Na úvod skúsme vyhľadať cesty zo San Francisca do New Yorku. • inicializačný poddotaz zistí všetky mestá, do ktorých sa dá doletieť zo San Francisca jediným letom • rekurzívny poddotaz nájde všetky mestá, ktoré sú dosažitelné z pôvodných • pre každé dosiahnuté mesto sa zaznamená trasa a celková cena • nakoniec sa zo získaných ciest vyberú tie, ktoré končia v New Yorku
WITH cesty(do,trasa,cena) AS ((SELECT do,do,cena FROM lety WHERE z=‘San Francisco’) UNION ALL (SELECT l.do, c.trasa ||’,’|| l.do, c.cena+l.cena FROM cesty c,lety l WHERE c.do=l.z)) SELECT trasa,cena FROM cesty WHERE do=‘New York’; Realizácia
WITH cesty(do,trasa,cena) AS ((SELECT do,do,cena FROM lety WHERE z=‘San Francisco’) UNION ALL (SELECT l.do, c.trasa ||’,’|| l.do, c.cena+l.cena FROM cesty c,lety l WHERE c.do=l.z)) SELECT trasa,cena FROM cesty WHERE do=‘New York’; Dva problémy: do stĺpca trasa vkladáme stále dlhší a dlhší reťazec (musíme systému nejakým spôsobom oznámiť jeho maximálnu dĺžku) dotaz neskončí, kým systému nedôjdu prostriedky Realizácia
CAST výraz • zmena hodnoty z jedného dátového typu na iný • definované v SQL92 • cieľový dátový typ musí byť dobre definovaný (veľkosť, rozsah, presnosť – ak je def.) • nastavené hodnoty sú Decimal(5,0), Char(1), Graphic(1) • ostatné typy bez hodnôt • nemožnosť konverzie • pri nezhode veľkostí CAST ( výraz AS typ ) NULL CAST (c1+c2 AS Decimal(8,2)) CAST (meno || adresa AS Varchar(255)) CHYBA zaokrúhlenie
Riešenie prvého problému • systém od nás potrebuje informáciu o tom, kam až môže narásť dĺžka položky • môžme určiť, že dĺžka trasy môže byť obmedzená na 100 znakov (čo je dosť miesta pre trasy, ktoré nás zaujímajú) • pomocou pretypovania stĺpca na Varchar(100) v inicializačnom aj rekurzívnom poddotaze sa s týmto problémom vysporiadame • zmeny: • inicializačný poddotaz: CAST(do AS Varchar(100)) • rekurzívny poddotaz: CAST(c.trasa ||’,’|| l.do AS Varchar(100))