Petr Čermák Michal Danihelka

Slides:



Advertisements
Podobné prezentace
Aplikační a programové vybavení
Advertisements

KIV/ZIS Cvičení 6 SQL - SELECT.
Základy jazyka SQL Jan Tichava
SQL: DDL v ORACLE CREATE TABLE jméno_tabulky (atribut datový_typ [DEFAULT][attribut_constraint] [, atribut datový_typ [DEFAULT] [attribut_constraint]],...
Aplikační a programové vybavení
Jazyk SQL Ing. Zdena DOBEŠOVÁ. SQL Structured Query Language 1974 SEQUEL (Structured English Query Language) neprocedurální relační dotazovací jazyk norma.
DB1 – 9. cvičení Optimalizace dotazu Konkurenční přístup a deadlock Indexace Transakce.
YDASYS1 Ing. Monika Šimková.
Fakulta elektrotechniky a informatiky
Informační systémy Nástroje pro sběr dat, návrh a realizace databáze.
Další dotazy SQL Structured Query Language. Některé SQL příkazy mohou mít v sobě obsaženy další kompletní příkazy SELECT. Využijeme je tam, kde potřebujeme.
Informatika pro ekonomy II přednáška 11
Architektury a techniky DS Tvorba efektivních příkazů I Přednáška č. 3 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy 1 Cvičení č. 2 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
Databázové systémy I Přednáška č. 5 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy II Přednáška č. 6 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Fakulta elektrotechniky a informatiky
Temporální databáze a TSQL
SQL Lukáš Masopust Historie  Předchůdcem databází byly papírové kartotéky  děrný štítek  1959 konference  1960 – vytvořen jazyk COBOL.
SQL Lukáš Masopust Historie  Předchůdcem databází byly papírové kartotéky  děrný štítek  1959 konference  1960 – vytvořen jazyk COBOL.
Temporální Databáze Jaroslav Dražan. Čím se budeme zabývat Proč je čas v DB důležitý Práce s časem pomocí klasického SQL Reprezentace časové domény Spojování.
Radek Špinka Přepínače MSSQL výběr.
ADT Strom.
Medians and Order Statistics Nechť A je množina obsahující n různých prvků: Definice: Statistika i-tého řádu je i-tý nejmenší prvek, tj., minimum = statistika.
MySQL - Vytvoření nové tabulky  create table jméno_tabulky (jméno_položky typ_položky,... ) Přehled nejběžnějších datových typů Přehled nejběžnějších.
Databázové systémy II Přednáška č. 8 – Pohledy (Views)
Školení správců II. Petr Pinkas RNDr. Vít Ochozka.
Databázové systémy II Přednáška č. 9 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Fakulta elektrotechniky a informatiky
Stromy a hierarchické struktury v SQL Mária Szabó, Jirka Zouhar, Gergely Jakab.
Databázové systémy teorie a návrh relačních databázových systémů část II.
KIV/ZIS cvičení 6 Tomáš Potužák. Pokračování SQL Klauzule GROUP BY a dotazy nad více tabulkami Stáhnout soubor studenti_dotazy_sql.mdb.
Databázové systémy Přednáška č. 6.
SQL – základní pojmy Ing. Roman Danel, Ph.D.
SQL PVA Jan Hora. SQL „graficky“ Grafický vs. pravý SQL SELECT ORDED BY WHERE.
Rauer Luboš Kopic Petr Blažek Tomáš. Structured Query Language - dotazovací jazyk -> pracuje s dotazy - neprocedurální jazyk - mocný, ale přitom jednoduchý.
Architektury a techniky DS Cvičení č. 9 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy 2 Cvičení č. 10 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy II Cvičení č. 3 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Informatika II PAA DOTAZOVACÍ JAZYKY
Databázové systémy 2 Zkouška – 8:00. Příklad I – Procedura – 5 bodů Vytvořte proceduru P_ZK2(p_table_name VARCHAR2, p_min_nuls NUMBER, p_drop.
Dynamic SQL P. Částek. Dynamic SQL Embedded SQL je překládaný preprocesorem => za běhu nelze nechat uživatele rozhodovat o vzhledu samotných SQL příkazů.
Aplikační a programové vybavení
XQuery Dotazovací jazyk XML Daniel Privalenkov. O čem bude prezentace Nutnost dotazovacího jazyku v XML Rychlý přehled XQuery Několik příkladů.
Databázové systémy SQL Výběr dat.
TEMPORÁLNÍ DATABÁZE A TSQL2
Rekurzivní dotazy v SQL
Databázové Aplikace Slidy ke cvičení DBI026, část 3 KSI MFF UK Verze
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.
Databázové Aplikace Slidy ke cvičení DBI026, část 2 KSI MFF UK Verze
Databázové systémy I Přednáška č. 6 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Příkazy jazyka SQL ve VFP a na SQL Serveru
Perzistence XML dat Kamil Toman
Databázové systémy přednáška 6 – Indexy
SQL – příkaz SELECT Ing. Roman Danel, Ph.D.
Databázové systémy I Přednáška 5 Databázové systémy 1 – KIT/IDAS1
Databázové systémy I Přednáška 8 Databázové systémy 1 – KIT/IDAS1
Databázové systémy a SQL
Dotazovací jazyk SQL - III
Ing. Tomáš Váňa, Ing. Jiří Zechmeister
Databázové systémy a SQL
Databázové systémy a SQL
Databázové systémy a SQL
[ START WITH podmínka ] CONNECT BY podmínka
Optimalizace SQL dotazů
Databázové systémy a SQL
Přednáška 7 SQL – JOIN.
Přednáška 9 Triggery.
Databázové systémy a SQL
Transkript prezentace:

Petr Čermák Michal Danihelka Rekurzivní SQL Petr Čermák Michal Danihelka

Osnova Úvod do problematiky Rekurzivní SQL v Oraclu Řešení rekurzivních úloh bez podpory rekurzivního SQL Rekurzivní SQL v DB/2 Použití DB/2 UDF

Úvod do problematiky

Co je to rekurzivní dotaz? Dotaz je rekurzivní, pokud se záznamy odkazují sami na sebe pomocí primárního nebo cizího klíče. Vazba může být přímá, nebo i přes několik tabulek

Použití rekurzivních dotazů Obecně kdekoliv mají data hierarchickou strukturu Uspořádání organizace Struktura výrobku Rodinná hierarchie

Divergentní hierarchie Každý uzel má nejvýše jednoho otce Reprezentace tabulkou s poli Klíč, Otec a nějaká hodnota přiřazená objektu Kořen možno označit například Klíč = Otec klic = otec – dobre pred uvedenim rekurzivniho sql, nebot bylo mozno rozvinout hierarchii pomoci joinu. – Michal (??)... u rekurze riziko zacykleni Napriklad geograficke objekty... staty, kraje, okresy, mesta..

Konvergentní hierarchie Uzel může mít víc předků, nesmí však být svým otcem / dítětem (acyklický graf) Jedna tabulka nestačí Potřebujeme dvě – Objekty(PKey, Num) a Vztahy(PKey, CKey, Parametr vztahu) 2 tabulky – kdyz chceme u objektu mit vic info.. jinak by to tam bylo vickrat S tou jsme delali na zacatku.. Problem: A->B, A->C, B->D, C->D, kolik deti ma A? treba hierarchie ve firmach...

Rekurzivní hierarchie Graf může obsahovat i cykly Reprezentace stejná jako v předchozím případu Riziko zacyklení

Další dělení Vyvážené Nevyvážené Hladiny většinou různých typů Bývají divergentní Nevyvážené Hladiny prvků stejného druhu Zminit hierarchii s ukazately? (jde predevsim o strukturu) vs. data – nutno provadet i vypocty...

Podpora rekurze v SQL ANSI SQL nepodporuje dotazování popsaným způsobem ani výpočet obecně rekurzivních funkcí podpora je zahrnuta v „chystaném“ ANSI SQL3 (SQL:1999) náznaky implementace v ORACLE a DB2

Vlastnosti rekurzivních dotazů vše na jeden dotaz nepřehlednost výhodné pouze když využiji velkou část výsledkové sady

Jak se obejít bez rekurze? Použití cursorů, cyklů, ... Ztráta možnosti optimalizace Kód není tak “elegantní”

Požadavky kladené na rekurzi Při procházení grafem můžeme získat: dosažitelnost vyčíslitelnost cest spojování cest výpočet obecně rekurzivní funkce při průchodu vrcholem nebo hranou

Příklad: (vztahy mezi součástmi) 2 2 2 P2 P3 P4 3 2 1 3 P5 P6 P7 2 1 P8 P9

Dosažitelnost Z daného vrcholu, nebo množiny vrcholů, chceme zjistit všechny dosažitelné potomky “Z jakých částí se skládá výrobek P1?”

Vyčíslitelnost cest “Zobraz celou strukturu výrobku P1 se všemi jeho částmi” P1(1) 2 2 2 P2(2) P3(2) P4(2) 3 2 1 3 P5(6) P6(4) P6(2) P7(6) 2 1 2 1 P8(8) P9(4) P8(4) P9(4)

Spojování cest “Jaké jsou části výrobku P1 a kolik jich je třeba k jeho sestavení?” P1(1) 2 2 2 P2(2) P3(2) P4(2) 3 2 1 3 P5(6) P6(6) P7(6) 2 1 P8(12) P9(6)

Rekurzivní SQL v Oraclu

Co Oracle podporuje? dosažitelnost vyčíslitelnost cest jednu rekurzivní funkci level

Příklad: (struktura výrobku) CREATE TABLE Parts (part# CHAR(5) PRIMARY KEY, part_name CHAR(4) NOT NULL, assembly_time INTEGER NOT NULL CHECK (VALUE >= 0), category_id INTEGER NOT NULL, FOREIGN KEY category_id REFERENCES Category); CREATE TABLE Usage (parent_part# CHAR(5) NOT NULL, component_part# CHAR(5) NOT NULL, quantity INTEGER NOT NULL, PRIMARY KEY(parent_part#, component_part#), FOREIGN KEY parent_part# REFERENCES Parts, FOREIGN KEY component_part# REFERENCES Parts);

CONNECT BY, START WITH Klauzule START WITH CONNECT BY definuje počáteční podmínku pro dotaz CONNECT BY specifikuje vazbu mezi rodičovskými řádky a potomky (pomocí operátoru PRIOR)

Příklad: (zobraz strukturu výrobku – vyčíslitelnost cest) SELECT LEVEL, parent_part#, component_part# FROM Usage CONNECT BY PRIOR component_part# = parent_part# START WITH parent_part# = ‘P1’ Výsledek dotazu není tabulka, výsledek je nutně uspořádaný Omezení -- nemožnost počítat libovolnou obecně rekurzivní funkci omezení na používání spojení v rek. dotazech

Algoritmus zpracování dotazu 1) Zjisti řádky splňující podmínku v START WITH 2) Najdi všechny potomky vzhledem k řádkům z kroku 2 nebo předchozího kroku 3 splňující podmínku v CONNECT BY 3) Opakuj krok 3 dokud dostáváš nové řádky 4) Eliminuj všechny řádky, které nesplňují podmínku ve WHERE 5) Vrať zbylé řádky.

Pořadí vrácených řádků Řádky jsou vraceny v preorderu tj. nejdříve rodičovský vrchol, pak teprve podstromy.

Příklad: (Dosažitelnost) SELECT DISTINCT component_part# FROM (viz. select pro zobrazení struktury)

Příklad: (obcházení joinu v connect by – součástky s popisem) SELECT part#, category_name FROM Parts,Category WHERE Parts.category_id = Category.category_id AND part# IN (SELECT component_part# FROM Usage START WITH parent_part# = ‘P1’ CONNECT BY PRIOR componet_part# = parent_part#);

Příklad: (obcházení joinu v connect by – dosažitelné dvojice) SELECT DISTINCT PX.part#, PX.part_name#, PY.part#, PY.part_name# FROM Parts PX,Parts PY WHERE PY.part# IN (SELECT component_part# FROM Usage START WITH parent_part# = PX.part# CONNECT BY PRIOR componet_part# = parent_part#) ORDER BY PX.part#, PY.part#;

Rozšíření Oracle 9i – podpora join SELECT employee_name, manager_name, dept_name FROM employee, dept WHERE employee.deptno = dept.deptno START WITH employee_name = 'KING' CONNECT BY PRIOR employee_id = manager_id;

Rozšíření Oracle 9i – třídění řádků s daným předkem SELECT employee_name, manager_name, dept_name FROM employee, dept WHERE employee.deptno = dept.deptno START WITH employee_name = 'KING' CONNECT BY PRIOR employee_id = manager_id ORDER SIBLINGS BY hire_date;

Rozšíření Oracle 9i - cesty SELECT employee_name, SYS_CONNECT_BY_PATH(employee_name, '/') "PATH" FROM employee START WITH employee_name = 'KING' CONNECT BY PRIOR employee_id = manager_id;

Rozšíření Oracle 10g – společný předek SELECT DISTINCT CONNECT_BY_ROOT assembly_id, CONNECT_BY_ROOT assembly_name FROM bill_of_materials WHERE part_number = 1019 START WITH parent_assembly IS NULL CONNECT BY parent_assembly = PRIOR assembly_id; CONNECT_BY_ROOTASSEMBLY_ID CONNECT_BY_ROOTASSEMBLY 100 Automobile

Rozšíření Oracle 10g – jsem list? – část 1 SELECT ASSEMBLY_ID, RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity, CONNECT_BY_ISLEAF FROM bill_of_materials WHERE LEVEL <= 2 START WITH assembly_id = 100 CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ASSEMBLY_NAME QUANTITY CONNECT_BY_ISLEAF 100 Automobile 110 Combustion Engine 1 120 Body 130 Interior

Rozšíření Oracle 10g – jsem list? – část 2 SELECT ASSEMBLY_ID, RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity, CONNECT_BY_ISLEAF FROM bill_of_materials WHERE LEVEL = 2 START WITH assembly_id = 110 CONNECT BY parent_assembly = PRIOR assembly_id; ASSEMBLY_ID ASSEMBLY_NAME QUANTITY CONNECT_BY_ISLEAF 111 Piston 6 1 112 Air Filter 113 Spark Plug 114 Block 115 Starter System

Rozšíření Oracle 10g – cykly ASSEMBLY_NAME QUANTITY CONNECT_BY_ISCYCLE Automobile Combustion Engine 1 Piston 6 Air Filter Spark Plug Block SELECT RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name, quantity, CONNECT_BY_ISCYCLE FROM bill_of_materials START WITH assembly_id = 100 CONNECT BY NOCYCLE parent_assembly = PRIOR assembly_id;

Řešení rekurzivních úloh bez podpory rekurzivního SQL

Formáty pro tabulky jakožto výsledky dotazů – část 1 Na rozdíl od oracla nesmějí mít tyto tabulky žádné číslování, aby šli používat v poddotazech Formát dostupnosti (kam se všude dostanu z vrcholu) – stačí binární tabulka obsahující kořen a syna parent_part# component_part#

Formáty pro tabulky jakožto výsledky dotazů – část 2 Formát vyčíslování cest (struktura s počtem podčástí) – použijeme následující tabulku seq# level parent_part# componet_part# max_subtree_seq# total_quantify Formát spojování cest (seznam následníků s počtem) – použijeme následující tabulku parent_part# componet_part# total_quantify

Kterak použít ANSI SQL k vyhodnocení rekurzivních dotazů – část 1 Dostupnost SELECT DISTINCT parent_part#, component_part# FROM PartsPathEnum WHERE parent_part# = ‘P1’ Vyčíslování cest SELECT * ORDER BY squence#;

Kterak použít ANSI SQL k vyhodnocení rekurzivních dotazů – část 2 Spojování cest SELECT parent_part#, component_part#, SUM(total_quantity) FROM PartsPathEnum WHERE parent_part# = ‘P1’ GROUP BY parent_part#,component_part#;

Kde vzít tabulku vyčíslitelnosti cest? PL/SQL nebo jakýkoliv jazyk podporující rekurzi a SQL Doporučeno udělat index na kombinaci sloupců (parent_part#,component_part#), jelikož je tato tabulka typicky hodně veliká Není aktuální, ale v praxi většinou nevadí

Ořezávání dotazu SELECT PE1.* FROM PartsPathEnum PE1, PartsPathEnum PE2 WHERE PE1.parent_part# = ‘P1’ AND PE2.parent_part# = ‘P1’ AND PE2.component_part# = ‘P3’ AND (PE1.seq# NOT BETWEEN PE2.seq# AND PE2.max_subtree_seq#) ORDER BY PE1.seq#;

Rekurzivní SQL v DB/2

Úvodní příklad Úkol: Získat seznam potomků (i nepřímých) uzlu A. HIERARCHY A PKEY CKEY NUM A B 1 C 5 D 20 E 33 44 F G B C D E F G

Řešení PKEY CKEY A B C D E F G A B C D E F WITH PARENT (PKEY, CKEY) AS (SELECT PKEY, CKEY FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.PKEY, C.CKEY FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY ) SELECT PKEY, CKEY FROM PARENT; PKEY CKEY A B C D E F G G With definuje tzv. Common table expression. Tabulka, která trva pouze po dobu dotazu. Nepotrebuje vlastní tablespace.. (to samy jako select * from a as (select ...), b where a... Select, nebo Select All, select distinct není povolen.. Stejne jako pouze union all Typy sloupecku jsou urceny prvnim podselektem, který nesmi byt rekurzivni (jinak změna pomoci CAST) Rekurzivni dotaz nesmi obsahovat zadne group by, having.., nesmi obsahovat poddotaz odkazujici se na parent.

Řešení problému zacyklení Týká se rekurzivních hierarchií Dvě základní metody řešení: Zastavit procházení po určitém počtu hladin Udržovat si seznam navštívených uzlů a ignorovat dříve navštívené

Příklad 2 Seznam potomků s hloubkou, v jaké se nalézají. CKEY LVL A B F Seznam potomků s hloubkou, v jaké se nalézají. CKEY LVL A B 1 C D E 2 F G 3 G WITH PARENT (CKEY, LVL) AS (SELECT DISTINCT PKEY, 0 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY ) SELECT PKEY, CKEY FROM PARENT; Distinct u toho nerekurzivniho selectu nevadi. Po kliknuti se zobrazi tabulka.

Příklad 3 Seznam potomků hloubky max. 2 CKEY LVL A B 1 C D E 2 F A B C B 1 C D E 2 F G WITH PARENT (CKEY, LVL) AS (SELECT DISTINCT PKEY, 0 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY ) SELECT PKEY, CKEY FROM PARENT, WHERE LVL < 3; Vsichni vidi, ze to je osklivy...

Příklad 3 podruhé Seznam potomků hloubky max. 2 CKEY LVL A B 1 C D E 2 F Seznam potomků hloubky max. 2 CKEY LVL A B 1 C D E 2 F G WITH PARENT (CKEY, LVL) AS (SELECT DISTINCT PKEY, 0 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY AND P.LVL + 1 < 3 ) SELECT PKEY, CKEY FROM PARENT; Tohle uz je lepsi, nejenze je to efektivnejsi (neprohledava to celou hierarchii), ale taky zabranuje zacykleni.

Příklad 4 Výpis cesty, která má délku 4 CKEY LVL G 4 F 3 D 2 A 1 A B C WITH TEMP1 (CKEY, LVL) AS (SELECT DISTINCT PKEY, 1 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, TEMP1 P WHERE P.CKEY = C.PKEY AND P.LVL < 4 ), TEMP2 (CKEY, LVL) AS (SELECT CKEY, LVL FROM TEMP1, WHERE LVL = 4 UNION ALL SELECT C.PKEY, D.LVL – 1 FROM HIERARCHY C, TEMP2 D WHERE D.CKEY = C.CKEY ) SELECT * FROM TEMP2; CKEY LVL G 4 F 3 D 2 A 1 Takto lze definovat vic temp. pohledu najednou... takhle lze projit treba vic hierarchii v jednom dotazu... neni povoleno cyklicke volani.. tzn aby se temp1 odkazovala na temp2 a naopak. Pri ruznych dotazech – varovani, ze se muze zacyklit...

Příklad 5 Všichni potomci uzlu A do 4. hladiny HIERARCHY A B C D E F G PKEY CKEY A B C D E F G B C D Pribyl radek D A CREATE TABLE HIERARCHY (PKEY CHAR(03) NOT NULL, CKEY CHAR(03) NOT NULL, CONSTRAINT TBX1 PRIMARY KEY (PKEY, CKEY), CONSTRAINT TBC1 CHECK (PKEY <> CKEY), CONSTRAINT TBC2 CHECK (LOCATE(‘>’, PKEY) = 0), CONSTRAINT TBC3 CHECK (LOCATE(‘>’, CKEY) = 0)); CREATE UNIQUE INDEX TBLE_X1 ON HIERARCHY (CKEY, PKEY); INSERT INTO HIERARCHY VALUES (‘..’, ‘..’), (.... E F G

Příklad 5 - řešení A B C D E F G WITH PARENT (CKEY, LVL) AS B 1 C D E 2 F 3 G E F WITH PARENT (CKEY, LVL) AS (SELECT DISTINCT PKEY, 0 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY AND P.LVL + 1 < 4 ) SELECT PKEY, CKEY FROM PARENT; G Tohle uz tam jednou bylo... (to s tim PKEY – ziska to spravnej typ, chyba, kdyz to tam nebude) Nevyhody – musime mit odhad na lvl, dostali se nam tam duplikaty, navis s ruznymi hladinami...

Příklad 5 – lepší řešení A B C D E F G WITH PARENT (CKEY, LVL) AS (SELECT DISTINCT PKEY, 0 FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1 FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY AND P.LVL + 1 < 4 ), NO_DUPS (CKEY, LVL, NUM) AS (SELECT CKEY, MIN(LVL), COUNT(*) FROM PARENT GROUP BY CKEY ) SELECT CKEY, LVL, NUM FROM NO_DUPS; G CKEY LVL NUM A 2 B 1 C D E F G 3 Treba takhle bychom chteli spocitat hladinu.. Pouzity dve temporarni tabulka, aby se no_dups dalo jeste pripojit k jinym.

Příklad 6 Udržování seznamu navštívených uzlů A B C D E F G WITH PARENT (CKEY, LVL, PATH) AS (SELECT DISTINCT PKEY, 0, VARCHAR(PKEY, 20) FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT C.CKEY, P.LVL + 1, P.PATH || ‘>‘ || C.CKEY FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY AND LOCATE(C.CKEY || ‘>‘, P.PATH) = 0 ) SELECT CKEY, LVL, PATH FROM PARENT; CKEY LVL PATH A B 1 A>B C A>C D A>D E 2 A>C>E A>D>E F A>D>F G 3 A>D>F>G Typy sloupecku jsou urceny prvnim selektem. Naalokovat radeji velke, varchatr stejne zabira jen co potrebuje Zde se tvori cesta z korene do uzlu, ktery je prave prochazen. Viz. sloupec path Zabraneni vybrani jiz navstiveneho uzlu. (Tohle neuvazuje smycky) LOCATE vrati pozici podretezce, 0, kdyz se tam nevyskytuje. Vyuziva to toho, ze klic je definovan tak, ze nesmi obsahovat znak >, viz Je to efektivnejsi, nez orezavani dle lvl, protoze to do nekonecnych cyklu vubec nevleze.

Definice tabulky pro př. 6 CREATE TABLE HIERARCHY (PKEY CHAR(3) NOT NULL, CKEY CHAR(3) NOT NULL, CONSTRAINT TBX1 PRIMARY KEY (PKEY, CKEY), CONSTRAINT TBC1 CHECK (PKEY <> CKEY), CONSTRAINT TBC2 CHECK (LOCATE(‘>’, PKEY) = 0), CONSTRAINT TBC3 CHECK (LOCATE(‘>’, CKEY) = 0)); CREATE UNIQUE INDEX TBLE_X1 ON HIERARCHY (CKEY, PKEY); TBC1 Zabrani smyckam TBC2, 3 Zabrani vyskytu > v klicich. Pokud mame klice ciselne, staci na ne pouzit funkci CHAR

Příklad 7 – Detekce cyklů WITH PARENT (CKEY, LVL, PATH) AS (SELECT DISTINCT PKEY, VARCHAR(PKEY, 20) FROM HIERARCHY WHERE PKEY = ‘A‘ UNION ALL SELECT CASE WHEN LOCATE(C.CKEY || ‘>‘, P.PATH) > 0 THEN RAISE_ERROR(‘70001‘, ‘CHYBA: Graf obsahuje cyklus‘); ELSE C.CKEY END, P.PATH || ‘>‘ || C.CKEY FROM HIERARCHY C, PARENT P WHERE P.CKEY = C.PKEY ) SELECT CKEY, PATH FROM PARENT; A B C D Driv, nez vleze do cyklu, vyhodi chybu E F G

Př. 8 - Tvorba syntetických dat Ve spojení s INSERT CREATE TABLE NUMBERS(COUNTER INTEGER, RANDOM INTEGER) INSERT INTO NUMBERS(COUNTER, RANDOM) WITH TEMP(N) AS (VALUES (1) UNION ALL SELECT N + 1 FROM TEMP WHERE N < 1000 ) SELECT N, INTEGER(RAND() * 1000) FROM TEMP;

Rekurze s počítáním Komponenty křídla letadla: Křídlo 5 1 1 8 Příčka Křidélko Podvozek Graf vyjadrujici, kolik ktera cast potrebuje komponent jineho typu 3 100 5 2 Pant 10 4 Nýt

Příklad 9 Počet nýtů COMPONENTS PART SUBPART QTY Křídlo Příčka 5 Křidélko 1 Podvozek Nýt 100 10 Pant 2 3 8 4 WITH WINGPARTS(SUBPART, QTY) AS (SELECT SUBPART, QTY FROM COMPONENTS WHERE PART = ‘Křídlo‘ UNION ALL SELECT C.SUBPART, P.QTY * C.QTY FROM WINGPARTS P, COMPONENTS C WHERE P.SUBPART = C.PART ) SELECT SUBPART, SUM(QTY) AS QTY FROM WINGPARTS WHERE SUBPART = ‘Nýt‘; Zde je priklad, proc muze rekurze potrebovat duplicity. Kliknuti – vysledek...

Příklad 9 - Výsledek Křídlo Příčka Křidélko Podvozek Pant Nýt 5 10 100 SUBPART QTY Příčka 5 Křidélko 1 Podvozek Nýt 100 50 Pant 2 3 8 12 Křídlo Příčka Křidélko Podvozek Pant Nýt 5 10 100 2 8 4 3 1 No..a pak uz staci bud select sum, where, nebo pokud chceme vsechny dily, tak GROUP BY SUBPART, SUM(QTY)

Použití DB/2 UDF

Kde rek. SQL DB/2 nestačí Problém: Nelze psát korelované rekurzivní poddotazy rekurzivních dotazů Příklad korelovaného poddotazu: SELECT POSSIBLE.ENAME, POSSIBLE.DEPT, POSSIBLE.SALARY FROM EMPLOYEE POSSIBLE WHERE SALARY > (SELECT AVG (SALARY) FROM EMPLOYEE AVERAGE WHERE POSSIBLE.DEPT = AVERAGE.DEPT); Jmeno, oddeleni, plat lib. zamestnance, ktery ma plat vyssi, nez prumer v jeho oddeleni Vyhodnoceni poddotazu zavisi na zpracovavanem radku vnejsiho dotazu. Neboli... je to poddotaz, kterej je spusten pro kazdou radku vnejsiho dotazu... Je to vlastne poruseni podminky acyklicnosti zavislosti mezi common table expressions.(?)

Příklad 10 Sporty Uživatelé Skupina A Skupina B Hobby Prof. Franta Fotbal Basket Karel Dokument 1 Dokument 2 Dokument 3

Příklad 10 - dotaz Potřebujeme zjistit, na jaké dokumenty ze stromu sportů má uživatel Karel přístup a ke kterým předmětům náleží. Musíme rozvinout hierarchii sportů pro získání dokumentů a pro každý dokument z hierarchie práv zjistit, zda na něj má Karel právo. Řešení - UDF user defined functions.. .driv v Java / C, ted uz i SQL

Příklad 10 – datový model Group Subject item_id parent_id item_name grp subgrp grpname Subject_Document Group_Document Document Dekompozice m:n item_id parent_id document_id grp subgrp document_id document_id name Tabulky: Subject, Group, Document, Subject_Document, Group_Document

Příklad 10 - Strategie Rozvineme hierarchii sportů -> získáme dokumenty (vnější rekurzivní dotaz)* Pro každý dokument z hierarchie sportů rozvineme skupiny uživatelů a zjistíme, zda se v nich nachází Karel (UDF s parametry ID dokumentu a uživatel) SELECT za * na každý vrácený dokument zavolá zmíněnou UDF

Příklad 10 - UDF CREATE FUNCTION ISELIGIBLE (Doc Integer, Uname character (64)) RETURNS INTEGER LANGUAGE SQL READS SQL DATA NO EXTERNAL ACTION NOT DETERMINISTIC RETURN WITH Main (subgrp, grpname) AS (SELECT subgrp, grpname FROM Group WHERE (subgrp) IN (SELECT subgrp FROM Group_Document WHERE document_id=Doc ) UNION ALL SELECT C.subgrp, C.grpname FROM Group C, Main M WHERE M.subgrp = C.grp ) SELECT COUNT(*) FROM main WHERE Ucase(grpname)=Ucase(Uname) Pokud tam neni, je tam 0 Prohlizi se smerem od group obsahujicich dokument DOLU. (smerem k uzivatelum)

Příklad 10 – Výsledný dotaz WITH Rpl (parent_id, item_id, item_name) AS (SELECT ROOT.parent_id, ROOT.item_id, ROOT.item_name FROM Subject ROOT WHERE ROOT.parent_id = 1 UNION ALL SELECT CHILD.parent_id, CHILD.item_id, CHILD.item_name FROM RPL PARENT, Subject CHILD WHERE PARENT.item_id = CHILD.parent_id ) SELECT DISTINCT Rpl.parent_id, Rpl.item_id, Rpl.item_name, document.document_id, document.name, ISELIGIBLE(document.document_id, char('Karel')) eligible FROM (Rpl JOIN Subject_Document sd ON Rpl.item_id = sd.item_id ) JOIN document ON document.document_id = sd.document_id; Predpokladame, ze Sport ma ID 1 (pokud tam maj bejt i ty druhyPK, tak tam prijde za ON jeste AND Rpl.parent_id = sd.parent_id