SQL - procedúry: Rozdiel medzi revíziami
d |
|||
(Jedna medziľahlá úprava od rovnakého používateľa nie je zobrazená.) | |||
Riadok 4: | Riadok 4: | ||
==Uložené procedúry== | ==Uložené procedúry== | ||
Uložená procedúra je sada príkazov SQL, ktoré sú: | Uložená procedúra je sada príkazov SQL, ktoré sú: | ||
− | * | + | *uložené na serveri, |
− | * | + | *skompilované pre rýchlejšie použitie<ref>mysql - uložené procedúry http://www.linuxsoft.cz/article.php?id_article=1003</ref>. |
Načo sú vlastne uložené procedúry v praxi dobré? Jedným dôvodom je fakt, že niektoré databázové operácie sa neustále opakujú. Ak je takáto databázová operácia vykonaná ako dávka na serveri, nemusia sa jednotlivé príkazy (ktorých môžu byť desiatky) vypisovať zakaždým, keď ich chceme vykonať. | Načo sú vlastne uložené procedúry v praxi dobré? Jedným dôvodom je fakt, že niektoré databázové operácie sa neustále opakujú. Ak je takáto databázová operácia vykonaná ako dávka na serveri, nemusia sa jednotlivé príkazy (ktorých môžu byť desiatky) vypisovať zakaždým, keď ich chceme vykonať. | ||
− | Ďalším dobrým dôvodom pre zavedenie uložených procedúr je istá unifikácia požiadaviek od jednotlivých klientov. Ak chce niekoľko databázových klientov vykonávať rovnakú (alebo | + | Ďalším dobrým dôvodom pre zavedenie uložených procedúr je istá unifikácia požiadaviek od jednotlivých klientov. Ak chce niekoľko databázových klientov vykonávať rovnakú (alebo veľmi podobnú) prácu, bude pre nich príjemné zistenie, že niečo také už server 'vie' vďaka uloženej procedúre, ktorú má k dispozícii. |
− | Uložené procedúry môžu tiež podstatným spôsobom uľahčovať spravovanie databázových aplikácií. Majme ako príklad server, ktorý ukladá a spracováva dáta. Ak to celé pobeží pomocou uložených procedúr, môžu | + | Uložené procedúry môžu tiež podstatným spôsobom uľahčovať spravovanie databázových aplikácií. Majme ako príklad server, ktorý ukladá a spracováva dáta. Ak to celé pobeží pomocou uložených procedúr, môžu sa rovnakým spôsobom voči databáze správať klienti pochádzajúci z najrôznejších prostredí - desktopová aplikácia napísaná v Jave, webový klient v PHP alebo napríklad vzdialený server, ktorý s tým 'naším' komunikuje. Ak je potreba uloženú procedúru upraviť (alebo opraviť), môže sa to urobiť na jednom mieste a táto zmena je ihneď použiteľná pre všetky aplikácie, ktoré s databázou komunikujú. |
− | Ďalším významným rysom uložených procedúr je to, že prispievajú k bezpečnosti | + | Ďalším významným rysom uložených procedúr je to, že prispievajú k bezpečnosti servera (respektíve môžu to robiť, ak sú dobre napísané). Keď hovoríme o bezpečnosti v súvislosti s uloženými procedúrami, môžeme mať na mysli dve veci: |
− | *Procedúry môžu byť v databázových systémoch nastavené tak, že | + | *Procedúry môžu byť v databázových systémoch nastavené tak, že ich smie spúšťať iba používateľ s určitými oprávneniami. |
− | *Procedúry môžu samy kontrolovať počet, typ, veľkosť a niektoré iné charakteristiky parametrov, ktoré sú im posielané. To je v praxi veľmi významné, pretože to umožňuje vyhnúť sa fenoménu SQL injection. | + | *Procedúry môžu samy kontrolovať počet, typ, veľkosť a niektoré iné charakteristiky parametrov, ktoré sú im posielané. To je v praxi veľmi významné, pretože to umožňuje vyhnúť sa fenoménu SQL injection<ref>SQL injection - http://en.wikipedia.org/wiki/SQL_injection</ref>. |
Je ale zaujímavé, že ani jeden z uvedených argumentov nie je pre nasadenie uložených procedúr ten najvýznamnejší. Zďaleka najdôležitejším argumentom pre nasadenie uložených procedúr na server býva to, že sú všeobecne '''schopné bežať rýchlejšie''', ako keby sa príslušný kód vykonával príkaz po príkaze z klientskej aplikácie. Dôvodom je fakt, že uložené procedúry, ako sme už uviedli, sú na serveri skompilované. | Je ale zaujímavé, že ani jeden z uvedených argumentov nie je pre nasadenie uložených procedúr ten najvýznamnejší. Zďaleka najdôležitejším argumentom pre nasadenie uložených procedúr na server býva to, že sú všeobecne '''schopné bežať rýchlejšie''', ako keby sa príslušný kód vykonával príkaz po príkaze z klientskej aplikácie. Dôvodom je fakt, že uložené procedúry, ako sme už uviedli, sú na serveri skompilované. | ||
− | Skompilovať uložené procedúry neznamená, že je táto procedúra prevedená do spustiteľnej, | + | Skompilovať uložené procedúry neznamená, že je táto procedúra prevedená do spustiteľnej, binárnej formy, ani to, že je uložená do samostatného súboru. Skompilovaním je myslené to, že server si pre uloženú procedúru vytvorí a spravuje tzv. realizačný plán. Vďaka tomu je subsystém serveru zvaný optimalizátor zvyčajne schopný nájsť najrýchlejší spôsob, ako uloženú procedúru vykonať, a potom tento spôsob opakovane používať pri jednotlivých volaniach tejto uloženej procedúry. |
===Čo môžu uložené procedúry robiť=== | ===Čo môžu uložené procedúry robiť=== | ||
Zjednodušene sa dá povedať, že uložené procedúry môžu robiť väčšinu z toho, čo 'bežné' príkazy. Medzi najčastejšie aktivity, ktoré taká uložená procedúra vykonáva, patria najmä: | Zjednodušene sa dá povedať, že uložené procedúry môžu robiť väčšinu z toho, čo 'bežné' príkazy. Medzi najčastejšie aktivity, ktoré taká uložená procedúra vykonáva, patria najmä: | ||
− | * | + | *vyberanie dát, |
− | * | + | *vkladanie, aktualizácia, odstraňovanie dát, |
− | * | + | *vytváranie, používanie a rušenie dočasných tabuliek, |
− | * | + | *matematické a štatistické výpočty. |
===Syntax vytvorenia uložených procedúr=== | ===Syntax vytvorenia uložených procedúr=== | ||
− | V databázovom systéme | + | V databázovom systéme MySQL je syntax CREATE PROCEDURE nasledovná<ref>create procedure (mysql) http://dev.mysql.com/doc/refman/5.5/en/create-procedure.html</ref>: |
<source lang="sql"> | <source lang="sql"> | ||
CREATE | CREATE | ||
Riadok 34: | Riadok 34: | ||
routine_body | routine_body | ||
− | proc_parameter: | + | proc_parameter::= |
[ IN | OUT | INOUT ] param_name type | [ IN | OUT | INOUT ] param_name type | ||
− | type: | + | type::= |
Ľubovolné dátové typy mySQL | Ľubovolné dátové typy mySQL | ||
− | routine_body: | + | routine_body::= |
Platný SQL príkaz | Platný SQL príkaz | ||
</source> | </source> | ||
Riadok 47: | Riadok 47: | ||
*''sp_name'' - názov uloženej procedúry. V názve nepoužívajte medzery a diakritiku. | *''sp_name'' - názov uloženej procedúry. V názve nepoužívajte medzery a diakritiku. | ||
*''proc_parameter'' - procedúra môže mať vstupné alebo výstupné parametre | *''proc_parameter'' - procedúra môže mať vstupné alebo výstupné parametre | ||
− | **IN - špecifikátor pre vstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru, ktorá z tabuľky city vypíše | + | **IN - špecifikátor pre vstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru, ktorá z tabuľky ''city'' vypíše mestá určitej krajiny. Kód krajiny chceme meniť, preto kód krajiny použijeme ako vstupný parameter procedúry. |
**OUT - špecifikátor pre výstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru ktorá vyhľadá v danej krajine (kód krajiny bude vstupným parametrom) mesto s najväčšou populáciou. Toto mesto bude výstupným parametrom procedúry. | **OUT - špecifikátor pre výstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru ktorá vyhľadá v danej krajine (kód krajiny bude vstupným parametrom) mesto s najväčšou populáciou. Toto mesto bude výstupným parametrom procedúry. | ||
Poznámky pri vytváraní uložených procedúr: | Poznámky pri vytváraní uložených procedúr: | ||
− | * | + | *Každý SQL príkaz musí byť ukončený ukončovacím znakom. |
− | *Štandardný ukončovací znak je bodkočiarka ';'. Avšak ak použijeme vo vnútri procedúry | + | *Štandardný ukončovací znak je bodkočiarka ';'. Avšak ak použijeme vo vnútri procedúry bodkočiarku, databázový systém to vyhodnotí ako ukončenie definície procedúry a pokúsi sa procedúru uložiť. Toto uloženie však skončí neúspechom, pretože procedúra nie je dokončená a sú tam syntaktické chyby. |
− | *Na dočasnú zmenu ukončovacieho znaku slúži príkaz DELIMITER. Zápisom DELIMITER // spôsobíme, že ukončovací znak nebude bodkočiarka (;) ale dve | + | *Na dočasnú zmenu ukončovacieho znaku slúži príkaz DELIMITER. Zápisom DELIMITER // spôsobíme, že ukončovací znak nebude bodkočiarka (;) ale dve lomky (//). |
Príklad najjednoduchšej procedúry: | Príklad najjednoduchšej procedúry: | ||
<source lang="sql" line> | <source lang="sql" line> | ||
− | + | DELIMITER // | |
− | + | CREATE PROCEDURE mesta() | |
− | + | BEGIN | |
− | + | SELECT * FROM city; | |
− | + | END // | |
− | + | DELIMITER ; | |
</source> | </source> | ||
Vysvetlenie: | Vysvetlenie: | ||
− | *Riadok 1: Ukončovací znak zmeníme na '//' | + | *Riadok 1: Ukončovací znak zmeníme na '//'. |
*Riadok 2: Definícia uloženej procedúry ''mesta''. Procedúra nemá žiadne parametre. | *Riadok 2: Definícia uloženej procedúry ''mesta''. Procedúra nemá žiadne parametre. | ||
− | *Riadok 3: Začiatok procedúry. Vždy sa začína kľúčovým slovom | + | *Riadok 3: Začiatok procedúry. Vždy sa začína kľúčovým slovom ''BEGIN''. |
− | *Riadok 4: Telo procedúry. Za každým SQL príkazom musí byť ukončovací znak bodkočiarka (;) | + | *Riadok 4: Telo procedúry. Za každým SQL príkazom musí byť ukončovací znak bodkočiarka (;). |
− | *Riadok 5: Koniec procedúry. Vždy sa končí kľúčovým slovom end. Procedúra musí byť ukončená ukončovacím znakom (pozor, nie bodkočiarka!) | + | *Riadok 5: Koniec procedúry. Vždy sa končí kľúčovým slovom end. Procedúra musí byť ukončená ukončovacím znakom (pozor, nie bodkočiarka!). |
− | *Riadok 6: Vrátime naspäť význam znaku ';' | + | *Riadok 6: Vrátime naspäť význam znaku ';'. |
+ | |||
'''Spustenie uloženej procedúry''' | '''Spustenie uloženej procedúry''' | ||
Riadok 89: | Riadok 90: | ||
===Postup pri vytváraní uložených procedúr v prostredí MySQL Workbench=== | ===Postup pri vytváraní uložených procedúr v prostredí MySQL Workbench=== | ||
− | '''1.''' V úvodnom okne programu | + | '''1.''' V úvodnom okne programu v ľavom stĺpci vyberieme databázové spojenie. |
[[Súbor:uložená procedúra 1.png|center|frame|Prostrenie MySQLWorkbench - pripojenie sa k databáze]] | [[Súbor:uložená procedúra 1.png|center|frame|Prostrenie MySQLWorkbench - pripojenie sa k databáze]] | ||
− | '''2.''' Vyberieme si databázu, s ktorou budeme pracovať. (V našom prípade, to bude databáza student) | + | '''2.''' Vyberieme si databázu, s ktorou budeme pracovať. (V našom prípade, to bude databáza ''student'') |
[[Súbor:uložená procedúra 2.png|center|framed|Prostrenie MySQLWorkbench - výber aktívnej databázy]] | [[Súbor:uložená procedúra 2.png|center|framed|Prostrenie MySQLWorkbench - výber aktívnej databázy]] | ||
Riadok 110: | Riadok 111: | ||
END$$ | END$$ | ||
</source> | </source> | ||
− | '''4.''' Zmeníme názov procedúry, doplníme telo procedúry a | + | |
+ | '''4.''' Zmeníme názov procedúry, doplníme telo procedúry a model synchronizujeme s databázovým serverom. | ||
+ | |||
Konkrétne príklady uložených procedúr sú v nasledujúcom texte. | Konkrétne príklady uložených procedúr sú v nasledujúcom texte. | ||
+ | |||
==Príklady na uložené procedúry== | ==Príklady na uložené procedúry== | ||
Riadok 145: | Riadok 149: | ||
''Analýza:'' | ''Analýza:'' | ||
− | Procedúra bude mať 1 vstupný parameter - názov kontinentu. V tabuľke country sú kontinenty zadefinované ako vymenovaný typ: 'Asia', 'Europe', 'North America', 'Africa', 'Oceania', 'Antarctica', 'South America'. Procedúra teda očakáva názov kontinentu a podľa tejto hodnoty vypíše hlavné mestá daného kontinentu. | + | Procedúra bude mať 1 vstupný parameter - názov kontinentu. V tabuľke ''country'' sú kontinenty zadefinované ako vymenovaný typ: 'Asia', 'Europe', 'North America', 'Africa', 'Oceania', 'Antarctica', 'South America'. Procedúra teda očakáva názov kontinentu a podľa tejto hodnoty vypíše hlavné mestá daného kontinentu. |
− | Názov procedúry bude HlavneMesta, parameter procedúry je vstupný parameter (IN). | + | Názov procedúry bude ''HlavneMesta'', parameter procedúry je vstupný parameter (IN). |
Riadok 155: | Riadok 159: | ||
CREATE PROCEDURE `student`.`HlavneMesta` (IN kontinent VARCHAR(16)) | CREATE PROCEDURE `student`.`HlavneMesta` (IN kontinent VARCHAR(16)) | ||
BEGIN | BEGIN | ||
− | SELECT Country.Name | + | SELECT Country.Name AS Krajina, City.Name AS Mesto |
FROM country, city | FROM country, city | ||
WHERE Capital=city.ID | WHERE Capital=city.ID | ||
− | + | AND Continent LIKE kontinent; | |
END$$ | END$$ | ||
</source> | </source> | ||
− | Výsledok: | + | Výsledok po zavolaní uloženej procedúry príkazom: ''CALL HlavneMesta('Africa')'' |
+ | |||
[[Súbor:uložená procedúra 3.png|center|frame|Výsledok po zavolaní procedúry HlavneMesta]] | [[Súbor:uložená procedúra 3.png|center|frame|Výsledok po zavolaní procedúry HlavneMesta]] | ||
+ | |||
===Procedúry s výstupnými parametrami=== | ===Procedúry s výstupnými parametrami=== | ||
'''Úloha:''' | '''Úloha:''' | ||
− | Vytvorte uloženú procedúru, ktorá vráti | + | Vytvorte uloženú procedúru, ktorá vráti názov krajiny, ktorá je v danom kontinente najľudnatejšia, teda má najviac obyvateľov |
Riadok 180: | Riadok 186: | ||
CREATE PROCEDURE `NajludnatejsiaKrajina`(IN kontinent VARCHAR(16), OUT nazov VARCHAR(32)) | CREATE PROCEDURE `NajludnatejsiaKrajina`(IN kontinent VARCHAR(16), OUT nazov VARCHAR(32)) | ||
BEGIN | BEGIN | ||
− | SELECT Name | + | SELECT Name FROM country WHERE population= |
( | ( | ||
SELECT MAX(population) FROM country WHERE Continent LIKE kontinent | SELECT MAX(population) FROM country WHERE Continent LIKE kontinent | ||
Riadok 186: | Riadok 192: | ||
END | END | ||
</source> | </source> | ||
+ | |||
Použite procedúry: | Použite procedúry: | ||
S výstupnými parametrami procedúr sa pracuje odlišne. Pri volaní takejto procedúry musíme určiť, kam sa hodnota výstupného parametra uloží a následne ju odtiaľ prečítať. Použitie procedúry pre zistenie krajiny v Afrike s najväčším počtom obyvateľov: | S výstupnými parametrami procedúr sa pracuje odlišne. Pri volaní takejto procedúry musíme určiť, kam sa hodnota výstupného parametra uloží a následne ju odtiaľ prečítať. Použitie procedúry pre zistenie krajiny v Afrike s najväčším počtom obyvateľov: | ||
+ | |||
<source lang="sql"> | <source lang="sql"> | ||
call NajludnatejsiaKrajina("Africa",@krajina); | call NajludnatejsiaKrajina("Africa",@krajina); | ||
select @krajina; | select @krajina; | ||
</source> | </source> | ||
− | Poznámka: Výsledok procedúry sa uloží do lokálnej premennej označenej ako @krajina. Príkazom select @krajina zistíme hodnotu tohoto parametru. | + | |
+ | Poznámka: Výsledok procedúry sa uloží do lokálnej premennej označenej ako ''@krajina''. Príkazom ''select @krajina'' zistíme hodnotu tohoto parametru. | ||
Riadok 203: | Riadok 212: | ||
|Nigeria | |Nigeria | ||
|} | |} | ||
+ | |||
===Procedúry s riadením vykonávania SQL príkazov=== | ===Procedúry s riadením vykonávania SQL príkazov=== | ||
− | V procedúrach môžeme používať aj príkazy na podmienené vykonávanie príkazov ( | + | V procedúrach môžeme používať aj príkazy na podmienené vykonávanie príkazov (''IF'') alebo cyklické opakovnaie vykonávania príkazov (''WHILE, FOR, DO''). |
Riadok 210: | Riadok 220: | ||
Vytvorte procedúru ''up_jazyky'' ktorá zistí počet oficiálnych, resp. neoficiálnych jazykov v danej krajine. O tom, či budeme počítať oficiálne alebo neoficiálne jazyky rozhodne parameter ''oficialne''. | Vytvorte procedúru ''up_jazyky'' ktorá zistí počet oficiálnych, resp. neoficiálnych jazykov v danej krajine. O tom, či budeme počítať oficiálne alebo neoficiálne jazyky rozhodne parameter ''oficialne''. | ||
+ | |||
Analýza úlohy: | Analýza úlohy: | ||
− | O tom, či je jazyk oficiálny alebo nie, hovorí atribút ''isOfficial'', ktorý môže nadobúdať hodnoty T (true) alebo F (false). Naša procedúra bude mať parameter ''oficialne'', ktorý bude typu boolean a teda môže nadobúdať len hodnoty ''true'' alebo ''false''. SQL príkaz, ktorý vyrieši danú úlohu je nasledovný: | + | |
+ | O tom, či je jazyk oficiálny alebo nie, hovorí atribút ''isOfficial'', ktorý môže nadobúdať hodnoty T (''true'') alebo F (''false''). Naša procedúra bude mať parameter ''oficialne'', ktorý bude typu boolean a teda môže nadobúdať len hodnoty ''true'' alebo ''false''. SQL príkaz, ktorý vyrieši danú úlohu je nasledovný: | ||
<source lang="sql"> | <source lang="sql"> | ||
− | SELECT CountryCode, | + | SELECT CountryCode, COUNT(CountryCode) FROM countryLanguage WHERE IsOfficial='T' GROUP BY CountryCode |
resp. | resp. | ||
− | SELECT CountryCode, | + | SELECT CountryCode, COUNT(CountryCode) FROM countryLanguage WHERE IsOfficial='F' GROUP BY CountryCode |
</source> | </source> | ||
− | Pre určenie ktorý SQL príkaz sa vykoná použijeme príkaz IF-ELSE. | + | Pre určenie ktorý SQL príkaz sa vykoná použijeme príkaz ''IF-ELSE''. |
− | Syntax príkazu IF je nasledovná: | + | |
+ | Syntax príkazu ''IF'' je nasledovná: | ||
<source lang="sql"> | <source lang="sql"> | ||
IF vyraz THEN | IF vyraz THEN | ||
Riadok 229: | Riadok 242: | ||
END IF; | END IF; | ||
</source> | </source> | ||
− | V prrípade, ak je splnený logický výraz pri príkaze IF, bude vykonaný prvý príkaz1, v opačnom prípade bude vykonaný SQL príkaz za kľúčovým slovom ELSE. Príkaz IF musí byť ukončený príkazom END IF | + | V prrípade, ak je splnený logický výraz pri príkaze IF, bude vykonaný prvý príkaz1, v opačnom prípade bude vykonaný SQL príkaz za kľúčovým slovom ELSE. Príkaz ''IF'' musí byť ukončený príkazom ''END IF;''. |
Riešenie príkladu bude nasledovné | Riešenie príkladu bude nasledovné | ||
Riadok 237: | Riadok 250: | ||
CREATE PROCEDURE `up_jazyky`(IN oficial boolean) | CREATE PROCEDURE `up_jazyky`(IN oficial boolean) | ||
BEGIN | BEGIN | ||
− | + | IF oficial=true THEN | |
− | SELECT CountryCode, | + | SELECT CountryCode, COUNT(CountryCode) AS pocet FROM countryLanguage WHERE IsOfficial='T' GROUP BY CountryCode; |
− | + | ELSE | |
− | SELECT CountryCode, | + | SELECT CountryCode, COUNT(CountryCode) AS pocet FROM countryLanguage WHERE IsOfficial='F' GROUP BY CountryCode; |
− | + | END IF; | |
END | END | ||
</source> | </source> | ||
+ | |||
Výsledok: | Výsledok: | ||
Riadok 275: | Riadok 289: | ||
+ | Poznámka: parameter ''oficial'' procedúry ''up_jazyky'' nedávame do úvodzoviek, lebo sa nejedná o reťazec, ale o logickú hodnotu. | ||
− | |||
− | |||
Aktuálna revízia z 23:29, 17. január 2011
Uložené procedúry sú špeciálne používateľom definované funkcie, ktoré sú uložené priamo na databázovom serveri, v konkrétnej databáze. MySQL podporuje uložené procedúry od verzie 5.
Uložené procedúry
Uložená procedúra je sada príkazov SQL, ktoré sú:
- uložené na serveri,
- skompilované pre rýchlejšie použitie[1].
Načo sú vlastne uložené procedúry v praxi dobré? Jedným dôvodom je fakt, že niektoré databázové operácie sa neustále opakujú. Ak je takáto databázová operácia vykonaná ako dávka na serveri, nemusia sa jednotlivé príkazy (ktorých môžu byť desiatky) vypisovať zakaždým, keď ich chceme vykonať.
Ďalším dobrým dôvodom pre zavedenie uložených procedúr je istá unifikácia požiadaviek od jednotlivých klientov. Ak chce niekoľko databázových klientov vykonávať rovnakú (alebo veľmi podobnú) prácu, bude pre nich príjemné zistenie, že niečo také už server 'vie' vďaka uloženej procedúre, ktorú má k dispozícii.
Uložené procedúry môžu tiež podstatným spôsobom uľahčovať spravovanie databázových aplikácií. Majme ako príklad server, ktorý ukladá a spracováva dáta. Ak to celé pobeží pomocou uložených procedúr, môžu sa rovnakým spôsobom voči databáze správať klienti pochádzajúci z najrôznejších prostredí - desktopová aplikácia napísaná v Jave, webový klient v PHP alebo napríklad vzdialený server, ktorý s tým 'naším' komunikuje. Ak je potreba uloženú procedúru upraviť (alebo opraviť), môže sa to urobiť na jednom mieste a táto zmena je ihneď použiteľná pre všetky aplikácie, ktoré s databázou komunikujú.
Ďalším významným rysom uložených procedúr je to, že prispievajú k bezpečnosti servera (respektíve môžu to robiť, ak sú dobre napísané). Keď hovoríme o bezpečnosti v súvislosti s uloženými procedúrami, môžeme mať na mysli dve veci:
- Procedúry môžu byť v databázových systémoch nastavené tak, že ich smie spúšťať iba používateľ s určitými oprávneniami.
- Procedúry môžu samy kontrolovať počet, typ, veľkosť a niektoré iné charakteristiky parametrov, ktoré sú im posielané. To je v praxi veľmi významné, pretože to umožňuje vyhnúť sa fenoménu SQL injection[2].
Je ale zaujímavé, že ani jeden z uvedených argumentov nie je pre nasadenie uložených procedúr ten najvýznamnejší. Zďaleka najdôležitejším argumentom pre nasadenie uložených procedúr na server býva to, že sú všeobecne schopné bežať rýchlejšie, ako keby sa príslušný kód vykonával príkaz po príkaze z klientskej aplikácie. Dôvodom je fakt, že uložené procedúry, ako sme už uviedli, sú na serveri skompilované.
Skompilovať uložené procedúry neznamená, že je táto procedúra prevedená do spustiteľnej, binárnej formy, ani to, že je uložená do samostatného súboru. Skompilovaním je myslené to, že server si pre uloženú procedúru vytvorí a spravuje tzv. realizačný plán. Vďaka tomu je subsystém serveru zvaný optimalizátor zvyčajne schopný nájsť najrýchlejší spôsob, ako uloženú procedúru vykonať, a potom tento spôsob opakovane používať pri jednotlivých volaniach tejto uloženej procedúry.
Čo môžu uložené procedúry robiť
Zjednodušene sa dá povedať, že uložené procedúry môžu robiť väčšinu z toho, čo 'bežné' príkazy. Medzi najčastejšie aktivity, ktoré taká uložená procedúra vykonáva, patria najmä:
- vyberanie dát,
- vkladanie, aktualizácia, odstraňovanie dát,
- vytváranie, používanie a rušenie dočasných tabuliek,
- matematické a štatistické výpočty.
Syntax vytvorenia uložených procedúr
V databázovom systéme MySQL je syntax CREATE PROCEDURE nasledovná[3]:
CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
routine_body
proc_parameter::=
[ IN | OUT | INOUT ] param_name type
type::=
Ľubovolné dátové typy mySQL
routine_body::=
Platný SQL príkaz
kde:
- DEFINER - používateľ, ktorému bude uložená procedúra patriť.
- sp_name - názov uloženej procedúry. V názve nepoužívajte medzery a diakritiku.
- proc_parameter - procedúra môže mať vstupné alebo výstupné parametre
- IN - špecifikátor pre vstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru, ktorá z tabuľky city vypíše mestá určitej krajiny. Kód krajiny chceme meniť, preto kód krajiny použijeme ako vstupný parameter procedúry.
- OUT - špecifikátor pre výstupný parameter. Ako príklad môžeme uviesť: vytvorte procedúru ktorá vyhľadá v danej krajine (kód krajiny bude vstupným parametrom) mesto s najväčšou populáciou. Toto mesto bude výstupným parametrom procedúry.
Poznámky pri vytváraní uložených procedúr:
- Každý SQL príkaz musí byť ukončený ukončovacím znakom.
- Štandardný ukončovací znak je bodkočiarka ';'. Avšak ak použijeme vo vnútri procedúry bodkočiarku, databázový systém to vyhodnotí ako ukončenie definície procedúry a pokúsi sa procedúru uložiť. Toto uloženie však skončí neúspechom, pretože procedúra nie je dokončená a sú tam syntaktické chyby.
- Na dočasnú zmenu ukončovacieho znaku slúži príkaz DELIMITER. Zápisom DELIMITER // spôsobíme, že ukončovací znak nebude bodkočiarka (;) ale dve lomky (//).
Príklad najjednoduchšej procedúry:
1 DELIMITER //
2 CREATE PROCEDURE mesta()
3 BEGIN
4 SELECT * FROM city;
5 END //
6 DELIMITER ;
Vysvetlenie:
- Riadok 1: Ukončovací znak zmeníme na '//'.
- Riadok 2: Definícia uloženej procedúry mesta. Procedúra nemá žiadne parametre.
- Riadok 3: Začiatok procedúry. Vždy sa začína kľúčovým slovom BEGIN.
- Riadok 4: Telo procedúry. Za každým SQL príkazom musí byť ukončovací znak bodkočiarka (;).
- Riadok 5: Koniec procedúry. Vždy sa končí kľúčovým slovom end. Procedúra musí byť ukončená ukončovacím znakom (pozor, nie bodkočiarka!).
- Riadok 6: Vrátime naspäť význam znaku ';'.
Spustenie uloženej procedúry
Uloženú procedúru môžeme spustiť pomocou kľúčového slova CALL [4]. Syntax je nasledovná:
CALL sp_name([parameter[,...]])
alebo
CALL sp_name[()]
Našu prvú procedúru spustíme nasledovne:
CALL mesta();
Poznámka k vytváraniu a spúšťaniu uložených procedúr: Pri vytváraní a spúšťaní uložených procedúr je vhodnejšie používať príkazový riadok (resp. databázovú konzolu), alebo nástroj, ktorý dovoľuje pracovať priamo v konzole. Takýmto prostredím je program MySQL Workbench. Prostredie phpMyAdmin nie je vhodné pre spúšťanie uložených procedúr.
Postup pri vytváraní uložených procedúr v prostredí MySQL Workbench
1. V úvodnom okne programu v ľavom stĺpci vyberieme databázové spojenie.
2. Vyberieme si databázu, s ktorou budeme pracovať. (V našom prípade, to bude databáza student)
3. Zvolíme 'Add routine' (pridať funkciu/procedúru). Otvorí sa sprievodca pridaním procedúry s predpripraveným kódom:
-- -----------------------------------------------
-- Routine DDL
-- -----------------------------------------------
DELIMITER $$
CREATE PROCEDURE `student`.`new_routine` ()
BEGIN
END$$
4. Zmeníme názov procedúry, doplníme telo procedúry a model synchronizujeme s databázovým serverom.
Konkrétne príklady uložených procedúr sú v nasledujúcom texte.
Príklady na uložené procedúry
Procedúry bez parametrov
Úloha:
Vytvorte uloženú procedúru, ktorá vráti všetky hlavné mestá Európy.
Analýza:
Procedúra nemá žiadne vstupné parametre. Úlohou je zistiť len hlavné mestá Európy. Pomocou jednoduchého SQL príkazu zistíme všetky hlavné mestá Európy. Procedúru nazvime HlavneMestaEuropy.
Riešenie:
DELIMITER $$
CREATE PROCEDURE `student`.`HlavneMestaEuropy` ()
BEGIN
SELECT Country.Name as Krajina, City.Name as Mesto
FROM country, city
WHERE Capital=city.ID
and Continent="Europe";
END$$
Procedúry so vstupnými parametrami
Úloha:
Vytvorte uloženú procedúru, ktorá vráti všetky hlavné mestá zadaného kontinentu.
Analýza:
Procedúra bude mať 1 vstupný parameter - názov kontinentu. V tabuľke country sú kontinenty zadefinované ako vymenovaný typ: 'Asia', 'Europe', 'North America', 'Africa', 'Oceania', 'Antarctica', 'South America'. Procedúra teda očakáva názov kontinentu a podľa tejto hodnoty vypíše hlavné mestá daného kontinentu. Názov procedúry bude HlavneMesta, parameter procedúry je vstupný parameter (IN).
Riešenie:
DELIMITER $$
CREATE PROCEDURE `student`.`HlavneMesta` (IN kontinent VARCHAR(16))
BEGIN
SELECT Country.Name AS Krajina, City.Name AS Mesto
FROM country, city
WHERE Capital=city.ID
AND Continent LIKE kontinent;
END$$
Výsledok po zavolaní uloženej procedúry príkazom: CALL HlavneMesta('Africa')
Procedúry s výstupnými parametrami
Úloha:
Vytvorte uloženú procedúru, ktorá vráti názov krajiny, ktorá je v danom kontinente najľudnatejšia, teda má najviac obyvateľov
Analýza:
Procedúra bude mať 1 vstupný parameter - názov kontinentu a jeden výstupný parameter - krajina, ktorú hľadáme. Procedúra očakáva názov kontinentu a podľa tejto hodnoty zistí krajinu, ktorá má v danom kontinente najväčšiu populáciu. Výstupný parameter označujeme značkou OUT.
Riešenie:
DELIMITER $$
CREATE PROCEDURE `NajludnatejsiaKrajina`(IN kontinent VARCHAR(16), OUT nazov VARCHAR(32))
BEGIN
SELECT Name FROM country WHERE population=
(
SELECT MAX(population) FROM country WHERE Continent LIKE kontinent
);
END
Použite procedúry:
S výstupnými parametrami procedúr sa pracuje odlišne. Pri volaní takejto procedúry musíme určiť, kam sa hodnota výstupného parametra uloží a následne ju odtiaľ prečítať. Použitie procedúry pre zistenie krajiny v Afrike s najväčším počtom obyvateľov:
call NajludnatejsiaKrajina("Africa",@krajina);
select @krajina;
Poznámka: Výsledok procedúry sa uloží do lokálnej premennej označenej ako @krajina. Príkazom select @krajina zistíme hodnotu tohoto parametru.
Výsledok:
Name |
---|
Nigeria |
Procedúry s riadením vykonávania SQL príkazov
V procedúrach môžeme používať aj príkazy na podmienené vykonávanie príkazov (IF) alebo cyklické opakovnaie vykonávania príkazov (WHILE, FOR, DO).
Úloha:
Vytvorte procedúru up_jazyky ktorá zistí počet oficiálnych, resp. neoficiálnych jazykov v danej krajine. O tom, či budeme počítať oficiálne alebo neoficiálne jazyky rozhodne parameter oficialne.
Analýza úlohy:
O tom, či je jazyk oficiálny alebo nie, hovorí atribút isOfficial, ktorý môže nadobúdať hodnoty T (true) alebo F (false). Naša procedúra bude mať parameter oficialne, ktorý bude typu boolean a teda môže nadobúdať len hodnoty true alebo false. SQL príkaz, ktorý vyrieši danú úlohu je nasledovný:
SELECT CountryCode, COUNT(CountryCode) FROM countryLanguage WHERE IsOfficial='T' GROUP BY CountryCode
resp.
SELECT CountryCode, COUNT(CountryCode) FROM countryLanguage WHERE IsOfficial='F' GROUP BY CountryCode
Pre určenie ktorý SQL príkaz sa vykoná použijeme príkaz IF-ELSE.
Syntax príkazu IF je nasledovná:
IF vyraz THEN
príkaz 1;
ELSE
príkaz 2;
END IF;
V prrípade, ak je splnený logický výraz pri príkaze IF, bude vykonaný prvý príkaz1, v opačnom prípade bude vykonaný SQL príkaz za kľúčovým slovom ELSE. Príkaz IF musí byť ukončený príkazom END IF;.
Riešenie príkladu bude nasledovné
DELIMITER $$
CREATE PROCEDURE `up_jazyky`(IN oficial boolean)
BEGIN
IF oficial=true THEN
SELECT CountryCode, COUNT(CountryCode) AS pocet FROM countryLanguage WHERE IsOfficial='T' GROUP BY CountryCode;
ELSE
SELECT CountryCode, COUNT(CountryCode) AS pocet FROM countryLanguage WHERE IsOfficial='F' GROUP BY CountryCode;
END IF;
END
Výsledok:
CALL up_jazyky(false) | CALL up_jazyky(true) | |||
CountryCode | pocet | CountryCode | pocet | |
---|---|---|---|---|
ABW | 3 | ABW | 1 | |
AFG | 3 | AFG | 2 | |
AGO | 9 | AIA | 1 | |
ALB | 2 | ALB | 1 | |
AND | 3 | AND | 1 | |
ANT | 1 | ANT | 2 | |
ARE | 1 | ARE | 1 |
Poznámka: parameter oficial procedúry up_jazyky nedávame do úvodzoviek, lebo sa nejedná o reťazec, ale o logickú hodnotu.
Úloha:
Vytvorte procedúru ktorá zabezpečí vloženie nového záznamu do tabuľky city. V prípade, ak s v tabuľke už dané mesto nachádza, záznam nevkladajte, ale aktualizujte pôvodný záznam.
Analýza:
Procedúra VlozMesto bude mať 4 vstupné parametre: názov mesta, kód krajiny, počet obyvateľov a okres. V prípade, ak ešte v tabuľke neexistuje dané mesto údaje vložíme pomocou príkazu INSERT, v opačnom prípade údaje aktualizujeme pomocou príkazu UPDATE.
DELIMITER $$
CREATE PROCEDURE `student`.`VlozMesto` (mesto CHAR(35), kod CHAR(3), okres CHAR(20), populacia INT)
BEGIN
IF EXISTS(SELECT * FROM city WHERE name LIKE mesto)THEN
UPDATE city SET CountryCode=kod , District=okres, Population=populacia WHERE name=mesto;
ELSE
INSERT INTO city (name, CountryCode, District, Popuslation) values (mesto, kod, okres, populacia);
end if;
END$$
Výsledok:
call VlozMesto("Soblahov","SVK","Trenciansky",2114);
ID | Name | CountryCode | District | Population |
---|---|---|---|---|
3210 | Košice | SVK | Východné Slovensko | 241874 |
3211 | Prešov | SVK | Východné Slovensko | 93977 |
3209 | Bratislava | SVK | Bratislava | 431061 |
4084 | Soblahov | SVK | Trenciansky | 2114 |
Druhé volanie tej istej procedúry:
call VlozMesto("Soblahov","SVK","Trenciansky",2345);
ID | Name | CountryCode | District | Population |
---|---|---|---|---|
3210 | Košice | SVK | Východné Slovensko | 241874 |
3211 | Prešov | SVK | Východné Slovensko | 93977 |
3209 | Bratislava | SVK | Bratislava | 431061 |
4084 | Soblahov | SVK | Trenciansky | 2345 |
Zdroje a odkazy
- ↑ mysql - uložené procedúry http://www.linuxsoft.cz/article.php?id_article=1003
- ↑ SQL injection - http://en.wikipedia.org/wiki/SQL_injection
- ↑ create procedure (mysql) http://dev.mysql.com/doc/refman/5.5/en/create-procedure.html
- ↑ call (mysql) http://dev.mysql.com/doc/refman/5.5/en/call.html