Rekurzivní dotazy v SQL

Slides:



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

KIV/ZIS Cvičení 6 SQL - SELECT.
SQL Další dotazy a pohledy
Základy jazyka SQL Jan Tichava
A5M33IZS – Informační a znalostní systémy Dotazovací jazyk SQL - I.
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.
Databázové systémy SQL Výběr dat.
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.
SQL Structured Query Language
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 II Přednáška č. 6 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
1 BUMI Úvod do medicínské informatiky Počítačové cvičení č. 3 Ing. Vratislav Čmiel.
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.
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.
Konceptuální návrh databáze
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 I Cvičení č. 6 Fakulta elektrotechniky a informatiky Univerzita Pardubice 2013.
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ý.
Číslo šablony: III/2 VY_32_INOVACE_P4_3.8 Tematická oblast: Aplikační software pro práci s informacemi II. Databáze – základy SQL Typ: DUM - kombinovaný.
Jazyk XML Jazyk pro tvorbu strukturovaných dokumentů Syntaxí velmi podobný HTML Hlavní cíle návrhu: Snadná editace - jazyk je textový Snadné strojové zpracování.
Databázové systémy 2 Cvičení č. 10 RNDr. David Žák, Ph.D. Fakulta elektrotechniky a informatiky
Databázové systémy II Přednáška č. 9. Transakce je logická jednotka práce sestávající z jednoho nebo více SQL příkazů, které jsou atomické z hlediska.
Optimalizace SQL dotazů Michal Kopecký
Konceptuální návrh databáze
Informatika II PAA DOTAZOVACÍ JAZYKY
Aplikační a programové vybavení
Obchodní akademie, Ostrava-Poruba, příspěvková organizace Vzdělávací materiál/DUM VY_32_INOVACE_01B13 Autor Ing. Jiří Kalousek Období vytvoření březen.
Základní obeznámení s jazykem SQL Databázové systémy.
Databázové systémy SQL Výběr dat.
TEMPORÁLNÍ DATABÁZE A TSQL2
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.
Petr Čermák Michal Danihelka
Databázové systémy I Cvičení č. 8 Fakulta elektrotechniky a informatiky Univerzita Pardubice 2015.
Příkazy jazyka SQL ve VFP a na SQL Serveru
David Gešvindr MCT | MSP | MCITP | MCPD. Jak se zpracovává dotaz? Když norma nestačila Práce s XML Geografická data CTE Zpracování hierarchií a grafů.
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
Ing. Tomáš Váňa, Ing. Jiří Zechmeister
Dotazovací jazyk SQL I.
Databázové systémy a SQL
Šablona 32 VY_32_INOVACE_038.ICT.34
[ START WITH podmínka ] CONNECT BY podmínka
A5M33IZS – Informační a znalostní systémy
Optimalizace SQL dotazů
Přednáška 7 SQL – JOIN.
Přednáška 9 Triggery.
Databázové systémy a SQL
Databázové systémy a SQL
Transkript prezentace:

Rekurzivní dotazy v SQL Martin Čermák Tomáš Dvořák Alena Rybičková

Úvod SQL příkaz rekurzivní SQL snaha o čitelnost, srozumitelnost dotaz je rekurzivní, pokud je použit ve své vlastní definici hůře čitelné i srozumitelné dotazy často jediný efektivní způsob získání výsledku bez rekurze je potřeba v hostitelském programu mít funkci, která zpracovává výsledky z dílčích dotazů výhodné pro hledání vztahů ve stromové struktuře lze použít pro acyklické i cyklické grafy

Syntaxe rekurzivního dotazu WITH [RECURSIVE] <query_alias_name> [ ( <column_list> ) ] AS ( <select_query> ) <query_using_query_alias_name> vše podstatné je uvnitř <select_query>

Použití klauzule WITH použitím klauzule WITH vzniká tzv. Common Table Expression (CTE) CTE je dočasný pohled (temporary view) požití CTE ve složitých dotazech, kde je nějaký poddotaz použit alespoň dvakrát v rekurzivních dotazech

Jednoduchý příklad Zamestnanec(Jmeno, Plat, Vedouci) hledáme zaměstnance, kteří mají plat alespoň 100.000 a jejichž přímý nadřizený je ‘Hoover’ SELECT Jmeno, Plat FROM Zamestnanec WHERE Vedouci = ‘Hoover’ AND Plat > 100000

Jednoduchý příklad – rekurze hledáme-li všechny zaměstnance, jejichž nadřízený (nemusí být přímý) je ‘Hoover’ potřebujeme rekurzivní dotaz použijeme klauzuli WITH definující “Common Table Expression” (CTE) obsahuje dvě části spojené klauzulí UNION ALL inicializační poddotaz bude zpracován jako první, neovlivňuje rekurzi v našem příkladě vyhledá Hooverovy přímé podřízené rekurzivní poddotaz přidává další záznamy k dočasnému pohledu (v závislosti na dříve nalezených) v našem příkladě zde budou přidáni zaměstnanci, jejich přímý nadřízený již byl přidán do dočasného pohledu

Jednoduchý příklad – rekurze WITH Adept (Jmeno, Plat) AS (( SELECT Jmeno, Plat [inicializační poddotaz] FROM Zamestnanec WHERE Vedouci = ‘Hoover’ ) UNION ALL ( SELECT Z.Jmeno, Z.Plat [rekurzívní poddotaz] FROM Adept AS A, Zamestnanec AS Z WHERE Z.Vedouci = A.Jmeno )) SELECT Jmeno [finální dotaz] FROM Adepti WHERE Plat > 100000;

Pravidla rekurzivního poddotazu nesmí obsahovat sloupcové opreace SELECT DISTINCT GROUP BY HAVING může obsahovat odkaz na výraz ve kterém je sám definovaný, ale ne poddotaz nižší úrovně každý sloupec rekurzivního poddotazu musí být typově kompatibilní s příslušným sloupcem v inicializačním poddotazu používá se přetypování – CAST

Složitější dotaz – nerekurzivní News(ID, Forum, Question) Hledáme fórum s nevyšším počtem příspěvků SELECT COUNT(ID) AS Nbr, Forum FROM News GROUP BY Forum HAVING COUNT(ID) = ( SELECT MAX(Nbr) FROM ( SELECT COUNT(ID) AS Nbr, Forum FROM News GROUP BY Forum ) Hledáme vlastně MAX(COUNT(...))

Příklad na použití klauzule WITH News(ID, Forum, Question) WITH Q_count_news (Nbr, Forum) AS ( SELECT COUNT(ID), Forum) FROM News GROUP BY Forum ) SELECT Nbr, Forum FROM Q_count_news WHERE Nbr = (SELECT MAX(Nbr) FROM Q_count_news)

Poznámky k příkladu dočasný pohled Q_count_news používáme pro zjednodušení zápisu SQL dotazu CTE (podobně jako pohled) musí mít název uvnitř CTE mohou být sloupce přejmenované

Použití více CTE v jednom dotazu WITH Q_count_news (Nbr, Forum) AS ( SELECT COUNT(ID), Forum FROM News GROUP BY Forum ), Q_max_count_news (Nbr) AS ( SELECT MAX(Nbr) FROM Q_count_news ) SELECT T1.* FROM Q_count_news T1 INNER JOIN Q_max_count_news T2 ON T1.Nbr = T2.Nbr

Rekurze v SQL rekurzivní dotaz má dvě části první část říká jak se má začít – bez rekurze druhá část říká jak má vypadat další krok obě části jsou spojeny pomocí klauzule UNION ALL rekurzivní dotaz vzniká použitím názvu CTE uvnitř druhé (rekurzivní) části dotazu je třeba definovat podmínky, za kterých je rekurze ukončena

Rekurze s výpočtem

Rekurze s výpočtem (2) Part Subpart Qty křídlo vzpěra 5 křidélko 1 podvozek nýt 100 10 pant 2 3 8 4

Rekurze s výpočtem (3) acyklický graf směr šipky říká z čeho je daný díl sestaven hodnoty u šipek říkají kolik daných součástek je použito u jednoho dílu každá řádka v tabulce je reprezentována šipkou

Rekurze s výpočtem (4) otázka: Kolik nýtů je použito při výrobě křídla? výpočet vyžaduje rekurzivní průchod grafem musíme sečíst nýty použité v jednotlivých součástech křídla u jednotlivých součástek musíme brát v úvahu jejich počet dotaz bude obsahovat obvyklé části inicializační poddotaz rekurzivní poddotaz finální dotaz

Rekurze s výpočtem – SQL dotaz WITH wingparts(subquery, qty) AS (( SELECT subpart, qty [inicializační poddotaz] FROM components WHERE part = ‘křídlo’ ) UNION ALL ( SELECT c.subpart, w.qty * c.qty [rekurzivní poddotaz] FROM wingparts w, components c WHERE w.subpart = c.part ));

Rekurze s výpočtem – průběh dotazu Subpart Qty vzpěra 5 přímé použití křidélko 1 podvozek nýt 100 50 z vzpěry pant 2 z křidélka 3 z podvozku 8 z pantu křidélka 12 z pantu podvozku

Rekurze s výpočtem – celý dotaz WITH wingparts(subquery, qty) AS (( SELECT subpart, qty [inicializační poddotaz] FROM components WHERE part = ‘křídlo’ ) UNION ALL ( SELECT c.subpart, w.qty * c.qty [rekurzivní poddotaz] FROM wingparts w, components c WHERE w.subpart = c.part )) SELECT sum(qty) AS qty [finální dotaz] FROM wingparts WHERE subpart = ‘nýt’; Výsledek: qty = 183

Databázové servery podporující rekurzivní dotazy MS SQL Server 2005 IBM DB2 v7.2 Oracle 9i podoruje jen procházení ve stromě – omezená syntaxe nepodporuje rekurzivní dotazy klauzule START WITH, CONNECT BY ...

Syntaxe průchodu stromů v Oracle 9i 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

Syntaxe průchodu stromů v Oracle 9i SELECT sloupce FROM tabulka [WHERE podmínka3] START WITH podmínka1 CONNECT BY podmínka2 [ORDER BY …] 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

Oracle 9i vs. ISO 1999 tabulka zaměstnanců: Emp(EmpNo, Name, Manager) Oarcle 9i: SELECT LPAD(’ ’, 2*Level) || Name Jmeno, Level FROM Emp START WITH Manager IS NULL CONNECT BY Manager = PRIOR EmpNo; ISO: WITH Emp AS ( SELECT EName AS Jmeno, 0 AS Level FROM Emp x WHERE Manager IS NULL UNION ALL SELECT EName, Level+1 FROM Emp y JOIN Emp ON y.Manager = Emp.EmpNo ) SELECT * FROM Emp;

SQL1999 a SQL Server 2005 Tomáš Dvořák

Syntaxe WITH [ RECURSIVE ] <query_alias_name> [ ( <column_list> ) ] AS ( <select_query> ) <query_using_query_alias_name> MS SQL Server 2005 zatím nepodporuje klíčové slovo RECURSIVE

Stromová struktura Id FatherID Name 1 NULL ALL 2 SEA 3 EARTH 4 AIR 5 SUBMARINE 6 BOAT 7 CAR Id FatherID Name 8 3 TWO WHEELES 9 TRUCK 10 4 ROCKET 11 PLANE 12 MOTORCYCLE 13 BICYCLE

Stromová struktura (2)

Stromová struktura – předchůdci ‘Motorcycle’ chceme zjistit všechny předchůdce „Motorcycle“ začneme řádkou obsahující „Motorcycle“ SELECT Name, FatherID FROM Vehicle WHERE Name = ‘Motorcycle’ dotaz provádějící další krok bude vypadat následovně: SELECT Name, FatherID FROM Vehicle

Stromová struktura – předchůdci ‘Motorcycle’ (2) oba předchozí dotazy spojíme pomocí klauzule UNION ALL WITH tree (date, id) AS ( SELECT Name, FatherID FROM Vehicle WHERE Name = ‘Motorcycle’ UNION ALL SELECT Name, FatherID FROM Vehicle )

Stromová struktura – předchůdci ‘Motorcycle’ (3) posledním krokem k rekurzi je vytvoření cyklu WITH tree (date, id) AS ( SELECT Name, FatherID FROM Vehicle WHERE Name = ‘Motorcycle’ UNION ALL SELECT Name, FatherID FROM Vehicle V INNER JOIN tree t ON t.id = V.ID ) SELECT * FROM tree

Stromová struktura – předchůdci ‘Motorcycle’ (4) Výsledek našeho dotazu tedy je: Data Id MOTORCYCLE 8 TWO WHEELES 3 EARTH 1 ALL NULL

Předchůdci bez rekurze (1) Dá se rekurze odstranit? ANO, pomocí zásobníku. Do tabulky přidáme 2 nové sloupečky: RIGHTBOUND a LEFTBOUND Joe Celko: „SQL for smarties“ kapitola „Trees and Hierarchies“

Předchůdci bez rekurze (2) Tabulku naplníme daty, pro nové sloupečky UPDATE VEHICLES SET LEFTBOUND = 1 , RIGHTBOUND = 26 WHERE ID = 1 UPDATE VEHICLES SET LEFTBOUND = 2 , RIGHTBOUND = 7 WHERE ID = 2 … UPDATE VEHICLES SET LEFTBOUND = 12 , RIGHTBOUND = 13 WHERE ID = 12 UPDATE VEHICLES SET LEFTBOUND = 14 , RIGHTBOUND = 14 WHERE ID = 13

Předchůdci - bez rekurze (3)

Předchůdci - bez rekurze (4) Dotaz na předchůdce MOTORCYCLE využije intervalů a bude vypadat: SELECT * FROM Vehicles WHERE RightBound > 12 AND LeftBound < 13

Zobrazení stromu (1) Někdy můžeme chtít zobrazit data v tabulce jako strom WITH tree (data, id, level, pathstr) AS (SELECT NAME, ID, 0, CAST('' AS VARCHAR(MAX)) FROM VEHICLE WHERE ID_FATHER IS NULL UNION ALL SELECT NAME, ID, t.level + 1, t.pathstr +’>’+ V.NAME FROM VEHICLE V INNER JOIN tree t ON t.id = V.ID_FATHER) SELECT SPACE(level) + data as data, id, level, pathstr FROM tree ORDER BY pathstr, id

Zobrazení stromu (2) Data Level PathStr All 1 Air Plane 2 Air>Plane Rocket Air>Rocket Earth Car Earth>Car Truck Earth>Truck 2Wheeles Earth>2Wheeles Bicycle 3 Earth>2Wheeles>Bicycle …

Zobrazení – bez rekurze (1) Do tabulky potřebujeme přidat sloupeček LEVEL, který nám označuje úroveň uzlu Spočítáme ji při vkládání uzlu UPDATE VEHICLES SET LEVEL = 0 WHERE ID = 1 UPDATE VEHICLES SET LEVEL = 1 WHERE ID = 2 … UPDATE VEHICLES SET LEVEL = 0 WHERE ID = 13 UPDATE VEHICLES SET LEVEL = 1 WHERE ID = 14

Zobrazení – bez rekurze (2) SELECT SPACE(level)+ name AS data FROM Vehicle ORDER BY LEFT_BOUND Data All Sea Submarine Boat Earth Car Two Wheeles Motorcycle

Mazání tabulek (1) Cíl: smazat tabulku Problém: tabulky jsou provázány integritními omezeními (FOREIGN KEY apod.) Co chceme: posloupnost jak máme mazat tabulky, abychom nakonec mohli smazat, tu kterou chceme Jak: pomocí rekurze projdeme tabulky, na kterých je integritní omezení

Mazání tabulek (1) WITH T_CONTRAINTES (table_name, father_table_name) AS ( SELECT DISTINCT CTU.TABLE_NAME, TCT.TABLE_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RFC INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE CTU ON RFC.CONSTRAINT_CATALOG = CTU.CONSTRAINT_CATALOG AND RFC.CONSTRAINT_SCHEMA = CTU.CONSTRAINT_SCHEMA AND RFC.CONSTRAINT_NAME = CTU.CONSTRAINT_NAME

Mazání tabulek (2) INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TCT ON RFC.UNIQUE_CONSTRAINT_CATALOG = TCT.CONSTRAINT_CATALOG AND RFC.UNIQUE_CONSTRAINT_SCHEMA = TCT.CONSTRAINT_SCHEMA AND RFC.UNIQUE_CONSTRAINT_NAME = TCT.CONSTRAINT_NAME WHERE CTU.TABLE_CATALOG = @DB AND CTU.TABLE_SCHEMA = @USR) ,

Mazání tabulek (3) T_TREE_CONTRAINTES (table_to_delete, level) AS ( SELECT DISTINCT table_name, 0 FROM T_CONTRAINTES WHERE father_table_name = @TABLE_TO_DELETE UNION ALL SELECT priorT.table_name, level - 1 FROM T_CONTRAINTES priorT INNER JOIN T_TREE_CONTRAINTES beginT ON beginT.table_to_delete = priorT.father_table_name WHERE priorT.father_table_name<>priorT.table_name)

Mazání tabulek (4) SELECT DISTINCT * FROM T_TREE_CONTRAINTES ORDER BY level

MS Server 2005 Počet rekurzivních volání je omezen na 100 Dá se ovlivnit nastavením OPTION (MAXRECURSION n) Beta verze zatím nepodporuje klíčové slovo RECURSION

Příklad – Hledání nejlepšího řešení Alena Rybičková

San Francisco – New York Flights flightno origin destination cost

San Francisco – New York hledáme jak se nejlevněji dostat ze San Francisca do New Yorku data obsahují cykly, musíme vyřešit abychom nelétali pořád dokola

Rekurzivní dotaz dočasný pohled nazvaný TRIPS tvoří UNION ALL mezi inicializačním poddotazem, který najde všechna města, do kterých se dá dostat ze SF na jeden let rekurzivním poddotazem, který najde najde všechna města, kam se lze dostat z již nalezených měst

První pokus WITH trips (destination, route, totalcost) AS ((SELECT destination, destination, cost [initial subquery] FROM flights WHERE origin = 'SanFrancisco’) UNION ALL (SELECT f.destination [recursive subquery] t.route || ',' || f.destination, t.totalcost + f.cost FROM trips t, flights f WHERE t.destination = f.origin)) SELECT route, totalcost [final query] FROM trips WHERE destination = 'NewYork';

Problémy porušení pravidla, že sloupce rekurzivního pododotazu nesmí být delsí než odpovídající sloupce inicializačního poddotazu do sloupce route vkládáme výraz, který roste při každém zavolání rekurzivního poddotazu ŘEŠENÍ: změníme datový typ u obou poddotazů (inicializační i rekurzivní) na Varchar(50)

CAST výrazy umožňuje změnit hodnotu z jednoho datového typu na jiný CAST ( výraz AS datový typ ) definuje se délka, rozsah, přesnost CAST (c1 + c2 AS Decimal(8,2)) CAST (name||address AS Varchar(255))

CAST výrazy implicitní hodnoty jsou Decimal(5,0), Char(1), Graphic(1) ostatní typy, pokud nejsou definované vlastnosti, při nemožnosti konverze – chyba string delší je doplněn mezerami kratší se uřízne a vrátí warning message

Řešení změníme datový typ u obou poddotazů (inicializační i rekurzivní) na Varchar(50) v inicializačním poddotazu nahradíme druhý sloupec CAST(destination AS Varchar(50)) v rekurzivním poddotaze CAST(t.route || ',' || f.destination as Varchar(50))

Problém zacyklení dotaz se nezastavi (dokud nevyčerpá prostředky), protože mapa je cyklický graf pravidla bránící zacyklení vyřaď všechny letové úseky které letí od SF - počátek letu vyřaď všechny letové úseky které letí z NY - cíl letu uvažuj jen lety s maximálně třemi úseky

Výsledný dotaz WITH trips (destination, route, nseg, totalcost) AS ((SELECT destination, CAST(destination AS Varchar(50)), 1, cost FROM flights WHERE origin = ‘SF' UNION ALL (SELECT f.destination CAST(t.route || ',' || f.destination AS Varchar(50)), t.nseg + 1, t.totalcost + f.cost FROM trips t, flights f WHERE t.destination = f.origin AND f.destination <> 'SF' AND f.origin <> 'NY’ AND t.nseg < 3)) SELECT route, totalcost FROM trips WHERE destination = ‘NY' AND totalcost= (SELECT min(totalcost) WHERE destination='NY');

Dotaz na nejmenší počet úseků cesta s nejmenším počtem úseků změníme final query SELECT route, totalcost [final query] FROM trips WHERE destination = 'NewYork' AND totalcost= (SELECT min(nseg) WHERE destination='NewYork');

Dotazy s více poddotazy rekurzivní dotazy nejsou omezené jedním inicializačním nebo jedním rekurzivním poddotazem všechny poddotazy jsou spojené pomocí UNION ALL letadla + vlaky chceme se nejlevněji dostat z SF do NY 2 inicializační poddotazy + 2 rekurzivní poddotazy

Dotaz s více poddotazy WITH trips (destination, route, nseg, totalcost) AS ((SELECT destination, CAST(destination AS Varchar(50)), 1, cost FROM flights WHERE origin = ‘SF') UNION ALL (SELECT destination, FROM trains WHERE origin = 'SF') UNION ALL (SELECT f.destination CAST(t.route || ',' || f.destination AS Varchar(50)), t.nseg + 1, t.totalcost + f.cost FROM trips t, flights f WHERE t.destination = f.origin AND f.destination <> 'SF' AND f.origin <> 'NewYork' AND t.nseg < 3)

Dotazy s více poddotazy UNION ALL (SELECT x.destination CAST(t.route || ',' || x.destination as Varchar(50)), t.nseg + 1, t.totalcost + x.cost FROM trips t, trains x WHERE t.destination = x.origin AND x.destination <> 'SF' AND x.origin <> 'NY’ AND t.nseg < 3) ) SELECT route, totalcost FROM trips WHERE destination = 'NY' AND totalcost= (SELECT min(totalcost) WHERE destination='NY');

Další použití rekurze

Rekurzivní vkládání tabulka je vytvořena a naplněna rekurzivním INSERT výrazem tabulka NUMBERS obsahuje sloupce COUNTER a RANDOM, COUNTER bude obsahovat čísla od 1 do 1000 a RANDOM náhodná čísla od 1 do 1000 pomocí funkce rand()

Rekurzivní vkládání 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;

Rekurzivní vkládání inicializační poddotaz je tvořen výrazem VALUES(1), určuje tabulku s jedním sloupcem a jedním řádkem obsahujícím 1 rekurzivní poddotaz vytváří sloupec 1000 po sobě jdoucích přirozených čísel koncový SELECT (vnořený v INSERTU) generuje 1000 náhodných čísel pomocí funkce rand()

Shrnutí dotaz tvoří UNION ALL, který se skládá z jednoho nebo více inicializačních a jednoho nebo více rekurzivních poddotazů každý inicializační poddotaz musí být nerekurzivní rekurzivní poddotaz používá výraz ve kterém je vložený rekurzivní poddotaz nesmí obsahovat sloupcové funkce, SELECT DISTINCT, GROUP BY, HAVING

Shrnutí sloupce rekurzivního poddotazu musí odpovídat (a nesmí být delší než) příslušnému sloupci inicializačního poddotazu rekurzivní poddotaz musí specifikovat jak je každý řádek spočítán z již existujícího řádku pokud data obsahují cykly, musí rekurzivní dotaz obsahovat pravidla pro zastavení při psaní koncového dotazu se použije rekurzivní výraz a další predikáty (např. pro nalezení nejlepších řešení)

Reference Don Chamberlin: Recursion in SQL: Tips and Techniques, May 1996 Frédéric BROUARD: Recursive Queries in SQL:1999 and SQL Server 2005, 2005 www.servercentral.com Srini Venigalla: Expanding Recursive Opportunities with SQL UDFs in DB2 v 7.2, March 2005