You are on page 1of 18

Programowanie serwera

Oracle 11g SQL i PL/SQL


Autor: Adam Pelikant
ISBN: 978-83-246-2429-4
Format: 158235, stron: 336

Twrz przejrzyste bazy danych i waciwie przetwarzaj informacje


Podstawy organizacja serwera, instalacja bazy danych i kocwki klienta
Jzyk SQL tworzenie rnych rodzajw zapyta, funkcjonalnoci dodatkowe
Jzyk PL/SQL procedury, funkcje, dynamiczny SQL
Bazy danych Oracle od lat stanowi najlepsz alternatyw dla wszystkich tych, ktrzy
potrzebuj funkcjonalnych i pojemnych struktur przechowywania danych,
wyposaonych dodatkowo w moliwo wszechstronnego przeszukiwania i zestawiania
potrzebnych informacji. Jednak podstawowa wiedza na temat rodowiska Oracle nie
wystarczy, aby zaprojektowa naprawd przejrzyst, prost w obsudze baz. Do tego
potrzebna jest solidna wiedza, ktr znajdziesz wanie w tym podrczniku.
Programowanie serwera Oracle 11g SQL i PL/SQL to kontynuacja ksiki Adama
Pelikanta Bazy danych. Pierwsze starcie, a poruszane w niej zagadnienia s bardziej
zaawansowane, cho przy odrobinie samozaparcia take nowicjusz w tej dziedzinie
bdzie w stanie przyswoi sobie zawart tu praktyczn wiedz. Oprcz organizacji
serwera, instalacji bazy danych i skadni jzyka SQL szczegowo omwione s tutaj
rne rodzaje zapyta w tym jzyku (prostych i zoonych), a take funkcje rozszerzenia
proceduralnego PL/SQL. W ksice opisano take zastosowanie Javy do tworzenia
oprogramowania po stronie serwera oraz funkcje analityczne, stanowice wstp do
przetwarzania OLAP. Cao uzupeniono praktycznymi przykadami, obrazujcymi
dziaanie poszczeglnych konstrukcji i procedur.
Organizacja serwera
Instalacja bazy i kocwki klienta
Zapytania wybierajce, modyfikujce dane i tworzce tabele
Dodatkowe funkcjonalnoci SQL
Procedury skadowane i wyzwalane
Funkcje w PL/SQL
Pakiety, kursory, transakcje
Dynamiczny SQL
Zastosowanie Javy do tworzenia oprogramowania po stronie serwera
Elementy administracji zarzdzanie uprawnieniami z poziomu SQL
Obiektowo w Oracle
Wydajna, bezpieczna i prosta w obsudze zaprojektuj doskona baz danych!

Spis treci
Od autora ......................................................................................... 5

Cz I

Oracle SQL ..................................................................... 7

Rozdzia 1. Wstp .............................................................................................. 9


Organizacja serwera ....................................................................................................... 10
Instalacja bazy i kocwki klienta .................................................................................. 12

Rozdzia 2. Zapytania wybierajce ................................................................... 27


Podstawowe elementy skadni ........................................................................................ 27
Grupowanie i funkcje agregujce ................................................................................... 36
Zapytania do wielu tabel zczenia ............................................................................ 40
Grupowanie i funkcje analityczne .................................................................................. 49
Funkcje analityczne i rankingowe .................................................................................. 63
Pozostae elementy skadniowe stosowane w SQL ........................................................ 87
Obsuga grafw w SQL .................................................................................................. 94

Rozdzia 3. Zapytania modyfikujce dane ......................................................... 99


Rozdzia 4. Zapytania tworzce tabele ........................................................... 103
Zapytania modyfikujce tabel ..................................................................................... 110
Dodatkowe informacje ................................................................................................. 114
Sekwencja ..................................................................................................................... 119
Perspektywy ................................................................................................................. 121
Indeksy ......................................................................................................................... 130

Rozdzia 5. Dodatkowe funkcjonalnoci SQL ................................................... 137


Zapytania dla struktur XML ......................................................................................... 137

Cz II

ORACLE PL/SQL ........................................................ 153

Rozdzia 6. PL/SQL ........................................................................................ 155


Podstawy skadni .......................................................................................................... 155

Rozdzia 7. Procedury skadowane .................................................................. 163


Rozdzia 8. Funkcje w PL/SQL ....................................................................... 179
Rozdzia 9. Pakiety ........................................................................................ 187

Spis treci

Rozdzia 10. Procedury wyzwalane ................................................................... 197


Rozdzia 11. Kursory ........................................................................................ 229
Rozdzia 12. Transakcje ................................................................................... 247
Rozdzia 13. Dynamiczny SQL ........................................................................... 253
Rozdzia 14. Zastosowanie Javy do tworzenia oprogramowania
po stronie serwera ....................................................................... 269
Rozdzia 15. Elementy administracji
zarzdzanie uprawnieniami z poziomu SQL ................................. 289
Rozdzia 16. Obiektowo w Oracle .................................................................. 301
Zakoczenie ................................................................................ 315
Skorowidz .................................................................................... 317

Rozdzia 7.

Procedury skadowane
Zamiast tworzy bloki anonimowe, wygodniej jest organizowa kod w nazwane procedury. W rodowisku baz danych nosz one miano procedur skadowanych. W przypadku jzykw wyszego rzdu taka organizacja kodu podyktowana jest chci utrzymania jego przejrzystoci jeli jego fragment ma by wykonywany wielokrotnie,
warto go umieci w procedurze i odwoywa si do niego tylko przez jej wywoywanie.
Take rne funkcjonalnoci, zadania kodu s argumentem za jego podziaem. Podstawowa skadnia polecenia tworzcego procedur ma posta:
CREATE PROCEDURE nazwa
IS
BEGIN
-- ciao procedury
END;

Zamiast sowa kluczowego IS mona stosowa tosame sowo kluczowe AS. Ciaem
procedury moe by dowolny zestaw instrukcji PL/SQL oraz dowolne zapytania SQL,
za wyjtkiem zapytania wybierajcego SELECT.
W przypadku rodowisk baz danych wydaje si jednak, e argumenty zwizane z organizacj kodu nie s tu najwaniejsze. Dla procedur skadowanych najpniej przy
pierwszym ich wykonaniu generowany jest plan wykonania zapyta wchodzcych w ich
skad, ich kod jest wstpnie optymalizowany, a nastpnie s one prekompilowane. W ten
sposb na serwerze przechowywana jest procedura w dwch postaciach: przepisu na
jej utworzenie CREATE PROCEDURE oraz skompilowanego kodu. Przy kadym nastpnym
wykonaniu odwoujemy si ju do postaci skompilowanej. Sprawia to, e procedury s
wykonywane szybciej i wydajniej ni ten sam kod w formie skryptu. Sprawa nie jest tak
oczywista w przypadku czsto wykonywanych zapyta. Plany wykonania kadego zapytania przechowywane s w pamici wspdzielonej (SGA System Global Area) i jeeli wykonamy je ponownie, wykorzystana zostanie jego przetworzona posta. Naley
jednak pamita, e zgodno dwch zapyta sprawdzana jest z dokadnoci do znaku,
nie jest natomiast analizowana semantyka. Poza tym informacje o planach zapyta s
nadpisywane na stare definicje w momencie wyczerpania zasobw pamici wspdzielonej. Bez wzgldu na te uwagi moemy jednak przyj, e wydajno przetwarzania
procedury skadowanej jest wiksza ni w przypadku rwnowanego jej skryptu (bloku
anonimowego). Jeeli chcemy usun definicj procedury, moemy uy nastpujcego
polecenia:

Cz II ORACLE PL/SQL

164
DROP PROCEDURE nazwa;

Wielokrotnie moemy chcie modyfikowa kod procedury. Ponowne wykonanie polecenia CREATE PROCEDURE spowoduje wykrycie obiektu o tej samej nazwie i wywietlenie komunikatu o bdzie. W zwizku z tym musimy najpierw usun definicj procedury, a nastpnie utworzy j ponownie. Zamiast tego moemy posuy si skadni
CREATE OR REPLACE PROCEDURE, ktra, w zalenoci od tego, czy procedura o danej nazwie ju istnieje, czy te nie, stworzy j od podstaw lub nadpisze na istniejcej now
definicj. Z punktu widzenia programisty nie da si rozrni, ktra z tych akcji zostaa
wykonana (taki sam komunikat Procedura zostaa pomylnie utworzona), dlatego,
korzystajc z tej skadni, naley si upewni, czy nadpisujemy kod waciwej procedury! Przykadem moe by utworzenie procedury, ktrej zadaniem bdzie zamiana
wszystkich nazwisk w tabeli Osoby na pisane duymi literami.
CREATE OR REPLACE PROCEDURE up
IS
BEGIN
UPDATE Osoby SET Nazwisko=UPPER(Nazwisko);
END;

Jak wida, ciao procedury zawiera zapytanie aktualizujce UPDATE zgodne ze skadni
SQL. Jej wywoanie moe odby si na przykad z wntrza bloku anonimowego o postaci:
BEGIN
up;
END;

Zamy, e w ramach tego samego skryptu chcielibymy sprawdzi poprawno wykonania procedury zapytaniem wybierajcym SELECT. Zgodnie z wczeniejsz uwag,
zamieszczenie go w ciele bloku anonimowego jest niedozwolone. Rwnie umieszczenie zapytania wybierajcego bezporednio po sowie kluczowym END; zakoczy
si komunikatem o bdzie. Std konieczno podzielenia skryptu na dwie czci, ktre
z punktu widzenia serwera stanowi bd osobne fragmenty. Znakiem odpowiedzialnym za taki podzia jest slash (/), przy czym czci bd traktowane jako fragmenty
kodu PL/SQL lub zapytania SQL, w zalenoci od zawartoci. Skrypt moe zosta
podzielony w ten sposb na dowoln liczb niezalenych fragmentw.
BEGIN
up;
END;
/
SELECT Nazwisko FROM Osoby;

Innym przykadem realizacji procedury skadowanej jest zastosowanie jej do przepisywania nazwisk i wzrostu osb do tabeli wys_tab, przy czym rekordy posortowane
bd malejco wedug wzrostu. Naley zauway, e tabela wys_tab o odpowiedniej
strukturze musi ju istnie w schemacie uytkownika.
CREATE OR REPLACE PROCEDURE wysocy
IS
BEGIN
INSERT INTO wys_tab(Nazwisko,Wzrost)
SELECT Nazwisko, Wzrost FROM Osoby
ORDER BY Wzrost DESC;
END wysocy;

Rozdzia 7. Procedury skadowane

165

W przedstawionym przykadzie definicja tworzonej procedury jest koczona poleceniem END nazwa;, gdzie nazwa jest jej nazw. Pominicie jej w tym poleceniu nie pociga za sob adnych zmian. Koczenie definicji procedury w prezentowany sposb
jest wskazane ze wzgldw organizacyjnych, porzdkowych, zwaszcza wtedy, kiedy
skrypt zawiera wiksz liczb zoonych procedur, co utrudnia znalezienie kocw definicji przy jego poprawianiu.
Dotychczas prezentowane przykady byy procedurami niepobierajcymi adnych danych z wywoujcego je skryptu byy bezparametrowe. Brak parametrw wywoania jest szczeglnie widoczny w drugim przypadku, gdzie do tabeli wys_tab trafiaj
wszyscy pracownicy wszyscy s traktowani jako wysocy. Zmodyfikujmy t procedur tak, aby do tabeli docelowej przepisywane byy tylko osoby wysze od pewnego
progu danego w postaci parametru.
CREATE OR REPLACE PROCEDURE wysocy
(mm number)
IS
BEGIN
INSERT INTO wys_tab(Nazwisko,wzrost)
SELECT Nazwisko, wzrost FROM Osoby
WHERE wzrost > mm
ORDER BY wzrost DESC;
END wysocy;

Jak pokazano, parametry procedury definiowane s w nawiasie po jej nazwie, a na minimaln definicj skada si nazwa i typ parametru, przy czym typ podawany jest bez
definiowania rozmiaru, czyli number, a nie number(10). Podanie rozmiaru w tym miejscu powoduje wywietlenie komunikatu o bdzie. Zdefiniowanie parametru procedury
sprawia, e jest on traktowany tak jak zadeklarowana zmienna i nie moe zosta zadeklarowany ponownie w jej ciele. Moe on zosta uyty w dowolnym miejscu definicji
procedury; w przedstawionym przykadzie zosta wykorzystany do sformuowania warunku w klauzuli WHERE zapytania wstawiajcego wiersze.
Jeeli chcemy uy w definicji procedury wicej ni jednego parametru, ich lista powinna by rozdzielona przecinkami. W przykadzie przedstawiono procedur, ktra
wstawia do tabeli Dodatki wiersze zawierajce sum wartoci brutto i staej danej drugim parametrem procedury Dodatek dla osoby, ktrej identyfikator zawiera pierwszy
z parametrw Num.
CREATE OR REPLACE PROCEDURE Dodaj
(Num number, Dodatek number)
IS
BEGIN
INSERT INTO Dodatki
SELECT Brutto+Dodatek FROM Zarobki
WHERE IdOsoby = Num;
END;

Jak przedstawiono to w dotychczasowych przykadach, zawarto procedury mog stanowi wszystkie zapytania modyfikujce dane, ale rwnie zapytania tworzce lub modyfikujce struktur bazy. Czasami jednak, zamiast wykonywa jakie operacje na danych, chcemy dokona operacji zwracajcej wynik w postaci zmiennej, np. policzy czy

Cz II ORACLE PL/SQL

166

podsumowa jak wielko zapisan w bazie. W takim przypadku w ciele procedury


wykorzystujemy bardzo czsto skadni SELECT ... INTO zmienna. Powoduje ona, e
wyznaczona zapytaniem warto skalarna jest przypisywana do zmiennej wystpujcej po sowie kluczowym INTO. Zapytanie takie nie skutkuje wyprowadzeniem danych
na standardowe wyjcie. Nie jest ono elementem SQL, a co za tym idzie, moe by
uywane tylko we wntrzu procedur i funkcji albo w blokach anonimowych PL/SQL.
Jeeli dokonujemy takiego przypisania do zmiennej, ktra jest parametrem procedury,
to parametr taki musi mie sufiks OUT wskazujcy, e jest on przekazywany z procedury do miejsca jej wywoania. Jeli nie zdefiniujemy parametru jako wychodzcego,
to prba przypisania mu wartoci spowoduje pojawienie si komunikatu o bdzie.
Wszystkie parametry, ktre nie maj jawnie okrelonego kierunku przekazywania danych, s domylnie typu IN, czyli przekazuj dane tylko do procedury. Dopuszczalny
jest jeszcze trzeci przypadek, w ktrym zarwno zmienna przekazywana jest do procedury, jak i obliczona wewntrz procedury warto przekazywana jest na zewntrz.
W takiej sytuacji zmienna jest opisywana par IN OUT. Prezentowana procedura zlicza
osoby wysze, ni to okrela warto progowa dana pierwszym parametrem.
CREATE OR REPLACE PROCEDURE wysocy
(mm number, ile OUT number)
IS
BEGIN
SELECT COUNT(wzrost) INTO ile FROM Osoby
WHERE wzrost > mm;
END wysocy;

Wywoanie tak zdefiniowanej procedury z bloku anonimowego wymaga zadeklarowania zmiennej, do ktrej zostanie przypisany parametr typu OUT. Musi ona mie typ
zgodny z parametrem formalnym, ale wymagane jest te podanie jego rozmiaru, o ile
typ nie oferuje rozmiaru domylnego. W prezentowanym przykadzie zadeklarowano
zmienn ile jako number (bo domylnie number number(10)). W przypadku zmiennych znakowych rozmiar pola musi by dany jawnie (varchar(11)). Wywoania procedury dokonujemy przez podanie jej nazwy oraz zdefiniowanie wartoci parametrw
czyli podanie listy parametrw aktualnych. Do parametrw typu IN moemy przypisywa zarwno zmienne, jak i stae, natomiast do parametrw typu OUT musimy
przypisa zmienne. W prezentowanym przykadzie nazwa zmiennej oraz parametru
w definicji procedury jest taka sama, co jest powszechnie stosowan notacj, cho ze
wzgldw skadniowych zgodno nazw nie jest wymagana.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(1.8, ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

Oczywicie procedura moe zawiera wicej ni jeden parametr typu OUT. Zamy,
e oprcz liczby osb o wzrocie wikszym od wartoci progowej chcemy wyznaczy
ich redni wzrost. Moemy zastosowa dwa zapytania agregujce, ktre okrel interesujce nas wartoci, jednak bardziej wydajne jest uycie podwjnego przypisania w zapytaniu SELECT ... INTO. Jeli zwraca ono jeden wiersz, to po sowie kluczowym INTO musimy umieci tyle zmiennych, ile wyrae jest wyznaczanych w jego pierwszej czci.

Rozdzia 7. Procedury skadowane

167

CREATE OR REPLACE PROCEDURE wysocy


(mm number, ile OUT number, sr OUT real)
IS
BEGIN
SELECT COUNT(wzrost), AVG(wzrost) INTO ile, sr FROM Osoby
WHERE wzrost > mm;
END wysocy;

Dla kadego parametru moe zosta zdefiniowana warto domylna. Wykonujemy to


przez podanie po typie zmiennej sowa kluczowego DEFAULT, po ktrym ustanawiana
jest warto. W prezentowanym przykadzie przyjto, e domyln wartoci progu,
od ktrego zliczamy osoby wysokie, jest 1.7.
CREATE OR REPLACE PROCEDURE wysocy
(mm NUMBER DEFAULT 1.7, ile OUT NUMBER)
IS
BEGIN
SELECT COUNT(wzrost) INTO ile FROM Osoby
WHERE wzrost > mm;
END wysocy;

Dla procedury ze zdefiniowan wartoci domyln poprawne jest wywoanie, w ktrym podajemy warto posiadajcego j parametru. Wwczas warto podana przy
wywoaniu nadpisuje si na domyln.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(1.8,ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

Jeeli jednak chcemy przy tak zdefiniowanych parametrach odwoa si do wartoci domylnej, to musimy zastosowa wywoanie nazewnicze o postaci parametr=>zmienna,
gdzie parametr jest nazw parametru formalnego procedury, a zmienna jest wartoci
aktualn tego parametru w miejscu, z ktrego j wywoujemy. Notacj t moemy
odczytywa jako parametr staje si zmienn. W przypadku takiego wywoania
zmienna, ktra nie zostaa w nim wymieniona, bdzie miaa przypisan warto domyln.
Gdyby w definicji procedury pominita w wywoaniu zmienna nie miaa zdefiniowanej
wartoci domylnej, to takie wywoanie spowodowaoby wywietlenie komunikatu
o bdzie.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(ile => ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

W definicji procedury zmieniamy kolejno parametrw tak, e drugi z nich ma przypisan warto domyln. Reszta procedury pozostaje bez zmian.

Cz II ORACLE PL/SQL

168
CREATE OR REPLACE PROCEDURE wysocy
(ile OUT NUMBER, mm NUMBER DEFAULT 1.7)
IS
BEGIN
SELECT COUNT(wzrost) INTO ile FROM Osoby
WHERE wzrost > mm;
END wysocy;

W takim przypadku, poniewa przy odwoaniu do wartoci domylnej pomijamy ostatni


parametr, dopuszczalne jest zastosowanie wywoania pozycyjnego. Jest ono dozwolone
wtedy, gdy pominiciu podlega n ostatnich parametrw posiadajcych wartoci domylne.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

Oczywicie bardziej oglne jest wywoanie nazewnicze, ktre, bez wzgldu na to, na
ktrych pozycjach znajduj si wartoci domylne, jest zawsze poprawne.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(ile => ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

Wywoanie nazewnicze jest dopuszczalne rwnie wtedy, kiedy podajemy peny zestaw parametrw. W takim przypadku kolejno ich wymieniania nie odgrywa adnej roli.
SET SERVEROUTPUT ON;
DECLARE
ile number;
BEGIN
wysocy(mm=>1.8, ile=>ile);
DBMS_OUTPUT.PUT_LINE(ile);
END;

Do wersji 11. moliwe byo stosowanie albo tylko wywoania pozycyjnego, albo nazewniczego jednoczesne uycie obu tych typw nie byo dozwolone. Od wersji 11.
istnieje ju taka moliwo. Przeanalizujmy to na przykadzie procedury o trzech parametrach numerycznych. Pierwsze dwa s typu IN, a trzeci typu OUT. W ciele procedury warto parametru wyjciowego c jest wyznaczana w postaci ilorazu dwch pierwszych parametrw.
CREATE OR REPLACE PROCEDURE dziel
(a real, b real, c OUT real)
AS
BEGIN
c:=a/b;
END;

Rozdzia 7. Procedury skadowane

169

W przykadowym skrypcie pokazane zostay poprawne wywoania tej procedury:


w peni pozycyjne, z dwoma pierwszymi parametrami danymi pozycyjnie oraz z danym
pozycyjnie pierwszym parametrem.
DECLARE
res real;
BEGIN
dziel(10, 9, res);
DBMS_OUTPUT.PUT_LINE('Wynik '
dziel(10, 9, c => res);
DBMS_OUTPUT.PUT_LINE('Wynik '
dziel(10, b => 9, c => res);
DBMS_OUTPUT.PUT_LINE('Wynik '
dziel(10, c => res, b => 9);
DBMS_OUTPUT.PUT_LINE('Wynik '
END;

|| res);
|| res);
|| res);
|| res);

Nie kade wywoanie mieszane jest jednak dopuszczalne. Dozwolone s tylko takie
przypadki, w ktrych pierwsze na licie parametry podstawiane s pozycyjnie, a pozostae nazewniczo. Kolejny przykad pokazuje niepoprawne uycie wywoania mieszanego, gdzie bd polega na tym, e rodkowy parametr jest dany nazewniczo, czyli,
inaczej mwic, e po parametrze danym nazewniczo istnieje cho jeden dany pozycyjnie.
DECLARE
res real;
BEGIN
dziel(10, b => 9, res);
DBMS_OUTPUT.PUT_LINE('Wynik ' || res);
END;

W przypadku prby wykonania takiego bloku anonimowego wygenerowany zostanie


komunikat o bdzie w nastpujcej postaci:
Error report:
ORA-06550: linia 12, kolumna 15:
PLS-00312: skojarzenie parametrw przez nazw moe nie implikowa skojarzenia przez pozycj
ORA-06550: linia 12, kolumna 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:

Ciekaw moliwoci zastosowania procedury jest wykonywanie zapyta skadanych


z fragmentw, np. danych statycznymi napisami czy te zawartych w zmiennej. Zbudujmy procedur, ktra w zalenoci od wartoci parametru zmieni sposb zapisu pola
Nazwisko w tabeli Osoby. Wykonanie takiego zapytania, skadajcego si z fragmentw
napisw, wymaga uycia polecenia EXECUTE IMMEDIATE.
CREATE OR REPLACE PROCEDURE exe_tekst
(typ varchar2)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE osoby SET Nazwisko=' || typ || '(Nazwisko)';
END exe_tekst;

Cz II ORACLE PL/SQL

170

Bardziej eleganckim rozwizaniem jest zastosowanie zmiennej pomocniczej zap, co


oczywicie nie wpywa na sposb wykonania. Przykad ten pokazuje natomiast, e miejscem deklaracji zmiennych lokalnych procedury (takich, ktre s widoczne tylko w jej
ciele) jest obszar midzy sowami kluczowymi IS oraz BEGIN. Przy deklarowaniu zmiennych w tym miejscu nie wolno stosowa sowa kluczowego DECLARE.
CREATE OR REPLACE PROCEDURE exe_tekst
(typ varchar2)
IS
zap varchar2(111);
BEGIN
zap:= 'UPDATE osoby SET Nazwisko=' || typ || '(Nazwisko)';
EXECUTE IMMEDIATE zap
END exe_tekst;

Przy okazji prezentowania tego przykadu chc przedstawi nieco archaiczne wywoanie procedury z zastosowaniem polecenia CALL. Poprawnymi parametrami s tu nazwy funkcji operujcych na zmiennych acuchowych: UPPER przepisanie acucha
do postaci pisanej tylko duymi literami, LOWER przepisanie acucha do postaci pisanej tylko maymi literami, INITCAP przepisanie acucha do postaci pisanej od
duej litery. Poprawne jest rwnie uycie pustego cigu znakw '' lub cigu ska'. Zalet tego typu wywoania jest moliwo zadajcego si z samych spacji '
stosowania bezporednio po nim zapytania wybierajcego, ktre ma za zadanie sprawdzi poprawno wykonania procedury.
CALL exe_tekst('UPPER');
SELECT * FROM osoby;

W wikszoci sytuacji bdziemy jednak stosowa klasyczne wywoanie wewntrz bloku


anonimowego. W takim przypadku zastosowanie w nim zapytania wybierajcego zgodnie z wymogami skadni nie jest dozwolone, jeli jednak chcemy w ramach tego samego skryptu wykona blok anonimowy i zapytanie wybierajce, musimy rozdzieli je
znakiem /. Faktycznie powoduje to, e pomimo tego, i oba elementy zapisane s w tym
samym miejscu, stanowi one dwa przetwarzane po sobie skrypty jeden PL/SQL,
drugi SQL. Kady duszy skrypt moe zosta podzielony znakami / na mniejsze fragmenty, ktre bd przetwarzane szeregowo, oczywicie pod warunkiem, e kady z nich
jest skadniowo poprawny.
BEGIN
exe_tekst('INITCAP');
END;
/
SELECT * FROM osoby;

Kolejny przykad przedstawia zastosowanie w definicji procedury wywoania wbudowanej procedury RAISE_APPLICATION_ERROR, ktra powoduje wygenerowanie (ustanowienie) bdu uytkownika o numerze danym pierwszym parametrem oraz komunikacie stanowicym drugi z parametrw. Naley zauway, e numeracja bdw w Oracle
przebiega przez wartoci ujemne, a dla bdw uytkownika zarezerwowano przedzia
<29999, 20001>. Wywoanie powyszej procedury powoduje przerwanie dziaania
programu i wywietlenie komunikatu o bdzie.

Rozdzia 7. Procedury skadowane

171

CREATE OR REPLACE PROCEDURE Blad


IS
BEGIN
RAISE_APPLICATION_ERROR (-20205, 'Bd programu');
END blad;

Bardziej zoonym przykadem zastosowania RAISE_APPLICATION_ERROR jest wykorzystanie jej podczas wykonywania procedury o ograniczonym zestawie danych wejciowych, co ma miejsce np. w opracowanej poprzednio procedurze exe_tekst. Jeeli
parametr wejciowy nie jest jednym z dopuszczalnych elementw wymienionych na
licie, generowany jest bd z odpowiednim komentarzem. W przeciwnym przypadku
wykonywane jest za pomoc polecenia EXECUTE IMMEDIATE zapytanie. Naley zwrci
uwag na fakt, e do porwnania z elementami listy uyto zmiennej przetworzonej do
postaci pisanej duymi literami UPPER(typ), gdy przy porwnywaniu acuchw
Oracle rozrnia ich wielko. Pozwala to na podanie w wywoaniu procedury nazwy
funkcji modyfikujcej acuch pisanej w dowolny sposb (literami maymi, duymi oraz
rnej wielkoci).
CREATE OR REPLACE PROCEDURE exe_tekst
(typ varchar2)
IS
BEGIN
IF UPPER(typ) NOT IN('UPPER', 'LOWER', 'INITCAP') THEN
RAISE_APPLICATION_ERROR (-20205, 'Za funkcja');
ELSE
EXECUTE IMMEDIATE
'UPDATE osoby SET Nazwisko=' || typ || '(Nazwisko)';
END IF;
END exe_tekst;

Moemy przeksztaci procedur, tak aby w jej ciele uy wywoania poprzednio utworzonej procedury generujcej bd przetwarzania o nazwie Blad.
CREATE OR REPLACE PROCEDURE exe_tekst
(typ varchar2)
IS
zap varchar2(111);
BEGIN
IF UPPER(typ) NOT IN('UPPER', 'LOWER', 'INITCAP') THEN
Blad;
ELSE
zap:= 'UPDATE osoby SET Nazwisko=' || typ || '(Nazwisko)';
EXECUTE IMMEDIATE zap;
END IF;
END exe_tekst;

Bdy mog si jednak pojawia podczas przetwarzania nie tylko na skutek celowej
dziaalnoci programisty, ale mog by te spowodowane nie zawsze dajcymi si
przewidzie zdarzeniami, bdnymi wywoaniami, nieodpowiednimi parametrami etc.
Moemy mwi wtedy o sytuacji wyjtkowej o powstaniu wyjtku. Takie zdarzenia
mog zosta w PL/SQL obsuone, oprogramowane.

Cz II ORACLE PL/SQL

172

Rozwamy przykad procedury, ktrej zadaniem jest okrelenie, czy pracownik o danym
numerze identyfikacyjnym IdOsoby, wskazanym parametrem num, istnieje w tabeli
Osoby. Jeli tak, drugi z parametrw (status) ma przyj warto 1; w przypadku
przeciwnym 0. W celu realizacji tego zadania zastosowano zapytanie wybierajce zwracajce do zmiennej pomocniczej kto identyfikator osoby. Jeeli pracownik o danym
identyfikatorze istnieje, warto zwrcona przez zapytanie i warto parametru bd
takie same, jeli jednak takiego pracownika nie ma, zapytanie wybierajce nie zwrci
adnego wiersza. Spowoduje to, e prba podstawienia pod zmienn kto zakoczy si
bdem przetwarzania: Nie znaleziono adnych wierszy. Stan ten moemy wykorzysta, wprowadzajc sekcj EXCEPTION i oprogramowujc wyjtek NO_DATA_FOUND, ktrego obsuga wykonywana jest wedug schematu WHEN nazwa_wyjtku THEN instrukcje.
W naszym przypadku obsuga wyjtku zawiera podstawienie odpowiedniej wartoci pod
zmienn status oraz wypisanie komunikatu.
CREATE OR REPLACE PROCEDURE czy_jest
(num IN NUMBER, status OUT NUMBER)
IS
kto NUMBER;
BEGIN
SELECT IdOsoby INTO kto
ROM Osoby WHERE IdOsoby = num;
IF (kto = num) THEN
status := 1;
DBMS_OUTPUT.PUT_LINE ('Pracownik istnieje');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
status := 0;
DBMS_OUTPUT.PUT_LINE('Pracownik nie istnieje');
WHEN OTHERS THEN
NULL;
END;

W rodowisku Oracle zdefiniowano wiele wyjtkw, ktrych nazwy symboliczne i przyczyny wystpienia zawiera tabela 7.1. Jeeli gdziekolwiek w ciele procedury wystpuje
sytuacja wyjtkowa, przetwarzanie przenoszone jest do sekcji obsugi wyjtkw. Najpierw sprawdzane jest to, czy wyjtek, ktry przerwa przetwarzanie, jest zgodny z nazw
symboliczn wystpujc w sekcji EXCEPTION. Nastpnie wykonywane s instrukcje znajdujce si po sowie kluczowym THEN jego obsugi, po czym przerywane jest przetwarzanie procedury i nastpuje powrt do miejsca, z ktrego zostaa ona wywoana. Jeli
w trakcie przetwarzania procedury pojawi si jednoczenie dokadnie dwa wyjtki,
co jest moliwe, chocia mao prawdopodobne, to obsuony zostanie tylko ten, ktry
wystpuje jako pierwszy na licie w sekcji obsugi wyjtkw. Na szczegln uwag
zasuguje wyjtek o nazwie OTHERS, ktry obsuguje wszystkie inne, dotd nieobsuone. Gdyby znalaz si on na pierwszym miejscu listy obsugi wyjtkw, to bez wzgldu
na to, jakie zdarzenie powodowaoby wystpienie sytuacji wyjtkowej, wykonywana
byaby zawsze ta sama sekcja znajdujca si po OTHERS. Od wersji 9. Oracle umieszczanie obsugi wyjtku OTHERS przed obsug jakiegokolwiek innego jest zabronione
skadniowo. Innymi sowy, jego obsuga musi by ostatnim elementem sekcji obsugi
wyjtkw. W prezentowanym przykadzie zastosowano minimaln obsug wyjtku
(sekcja nie moe by pusta) NULL, nie rb nic. Bez wzgldu na to, czy wyjtki s w procedurze obsugiwane, czy te nie, zasady jej wywoania pozostaj bez zmian.

Rozdzia 7. Procedury skadowane

173

Tabela 7.1. Wykaz najczciej wystpujcych wyjtkw serwera


Nazwa wyjtku

Numer bdu

Opis

NO_DATA_FOUND

ORA-01403

Jednowierszowe zapytanie wybierajce SELECT nie zwrcio


danych.

TOO_MANY_ROWS

ORA-01422

Zapytanie wybierajce SELECT zwrcio wicej ni jeden wiersz.

INVALID_CURSOR

ORA-01001

Niedopuszczalna operacja na kursorze.

ZERO_DIVIDE

ORA-01476

Prba dzielenia przez zero.

DUP_VAL_ON_INDEX

ORA-00001

Prba wstawienia powtarzajcej si wartoci w pole,


dla ktrego ustanowiono indeks unikatowy.

INVALID_NUMBER

ORA-01722

Konwersja acucha na liczb zakoczya si niepowodzeniem.

CURSOR_ALREADY_OPEN

ORA-06511

Prba otwarcia kursora, ktry ju zosta otwarty.

LOGIN_DENIED

ORA-01017

Prba zalogowania si z nieodpowiednim hasem lub loginem.

NOT_LOGGED_ON

ORA-01012

Prba wykonania polecenia operujcego na bazie danych


bez uprzedniego zalogowania si.

PROGRAM_ERROR

ORA-06501

PL/SQL napotka wewntrzny problem podczas przetwarzania.

STORAGE_ERROR

ORA-06500

PL/SQL dysponuje zbyt maymi zasobami pamici


lub pami zostaa uszkodzona.

TIMEOUT_ON_RESOURCE

ORA-00051

Zosta przekroczony czas oczekiwania na odpowied


bazy danych.

ACCESS_INTO_NULL

ORA-06530

Prba przypisania do zmiennej wartoci niezainicjowanej


(NULL).

CASE_NOT_FOUND

ORA-06592

adna z wartoci okrelonych warunkami WHEN w poleceniu


CASE nie jest prawdziwa, a nie wystpuje sekcja ELSE.

Wywoanie pozycyjne procedury moe mie posta:


SET SERVEROUTPUT ON;
DECLARE
kto NUMBER;
status NUMBER;
BEGIN
kto:=1;
czy_jest (kto, status);
DBMS_OUTPUT.PUT_LINE(status);
END;

Wywoanie nazewnicze mona zrealizowa wedug schematu:


SET SERVEROUTPUT ON;
DECLARE
kto NUMBER;
status NUMBER;
BEGIN
kto := 1;
czy_jest (status => status, num => kto);
DBMS_OUTPUT.PUT_LINE(status);
END;

Cz II ORACLE PL/SQL

174

Przedstawiony poprzednio przykad jest niewtpliwie akademicki, poniewa wykorzystuje sekcj obsugi wyjtkw do wyznaczania parametru OUT. W praktyce, jeli
w tym miejscu jest wyznaczany jaki parametr wyjciowy, to jest on odpowiedzialny
za kodowanie sposobu zakoczenia przetwarzania, np. 0 przetwarzanie zakoczone
sukcesem, <>0 przetwarzanie zakoczone niepowodzeniem; konkretna warto koduje przyczyn. Nasz procedur moglibymy wic doprowadzi do postaci, w ktrej
wykorzystywalibymy funkcj agregujc COUNT.
CREATE OR REPLACE PROCEDURE czy_jest
(num IN NUMBER, status OUT NUMBER, ok OUT NUMBER)
IS
BEGIN
ok:=0;
SELECT COUNT(IdOsoby) INTO status
FROM Osoby WHERE IdOsoby = num;
IF (status = 1) THEN
DBMS_OUTPUT.PUT_LINE ('Pracownik istnieje');
ELSE
DBMS_OUTPUT.PUT_LINE('Pracownik nie istnieje');
END IF;
EXCEPTION
WHEN OTHERS THEN
ok := 99;
DBMS_OUTPUT.PUT_LINE('Bd przetwarzania');
END;

Zamiana zapytania wybierajcego na takie, ktre zawiera funkcj zliczajc rekordy,


spowoduje, e jeli pracownik o danym numerze istnieje, to policzony zostanie 1 rekord, a jeli nie istnieje 0 rekordw. Jak wida, zmiana taka sprawia, e przypisanie
moe od razu dotyczy zmiennej wychodzcej oraz e wyjtek NO_DATA_FOUND nie pojawia si. Zawsze jednak moliwe jest wystpienie innych bdw przetwarzania, std
obsuga wyjtku OTHERS, w ktrej ustawiono zmienn ok na warto rn od zera, w tym
przypadku 99, co koduje stan pojawienia si bdu. Zwyczajowo pierwsz linijk ciaa
procedury jest ustawienie zmiennej kodujcej sposb wykonania na 0 przetwarzanie zakoczone poprawnie.
Istnieje formalna moliwo obsuenia dwch lub wicej wyjtkw w tym samym
miejscu sekcji ich obsugi. W tym celu po sowie kluczowym WHEN czymy nazwy symboliczne wyjtkw operatorem logicznym OR.
CREATE OR REPLACE PROCEDURE czy_jest
(num IN NUMBER, status OUT NUMBER, ok OUT NUMBER)
IS
BEGIN
ok := 0;
SELECT COUNT(IdOsoby) INTO status
FROM Osoby WHERE IdOsoby = num;
IF (status = 1) THEN
DBMS_OUTPUT.PUT_LINE ('Pracownik istnieje');
ELSE
DBMS_OUTPUT.PUT_LINE('Pracownik nie istnieje');
END IF;
EXCEPTION
WHEN INVALID_NUMBER OR NO_DATA_FOUND THEN

Rozdzia 7. Procedury skadowane

175

ok := 11;
DBMS_OUTPUT.PUT_LINE('Bd wartoci');
WHEN OTHERS THEN
ok := 99;
DBMS_OUTPUT.PUT_LINE('Bd przetwarzania');
END;

Nie zawsze jest tak, e wyjtek musi wiza si z formalnym bdem przetwarzania.
Czasami wygodnym jest, aby pewne sytuacje nieprowadzce do bdw formalnych
byy traktowane jako wyjtkowe. Mwimy wtedy o wyjtkach uytkownika, ktre musz
zosta zdefiniowane, wykryte i ktre powinny zosta obsuone. W prezentowanym
przykadzie za sytuacj wyjtkow bdziemy chcieli uzna fakt, e nie ma osb o wzrocie wyszym od progu danego parametrem. Jak wida, taka sytuacja nie spowoduje
powstania bdu przetwarzania trzeba wic j wykry.
CREATE OR REPLACE PROCEDURE licz
(mini NUMBER, ile out INT)
IS
brakuje EXCEPTION;
BEGIN
SELECT COUNT(IdOsoby) INTO ile FROM Osoby
WHERE Wzrost > mini;
IF (ile = 0) THEN
RAISE brakuje;
END IF;
EXCEPTION
WHEN brakuje THEN
RAISE;
WHEN OTHERS THEN
NULL;
END;

Deklaracji wyjtku uytkownika, tak samo jak kadej innej zmiennej, dokonujemy
w sekcji deklaracji i nadajemy mu typ EXCEPTION (jak wida, to sowo kluczowe peni
podwjn rol: jest okreleniem typu oraz sygnalizuje pocztek sekcji obsugi wyjtkw).
W przykadzie zdefiniowano wyjtek o nazwie brakuje. Po zliczeniu osb o wzrocie
wyszym od wartoci progowej instrukcj warunkow sprawdzono, czy ich liczba jest
rwna 0, po czym dla takiego przypadku poleceniem RAISE nazwa_wyjtku ustawiono
(wygenerowano) bd uytkownika. Obsugi wyjtku uytkownika dokonujemy na takich samych zasadach jak wyjtkw wbudowanych (systemowych). W przykadzie zastosowano drug, po minimalnej obsudze NULL, najczciej spotykan metod uycie
polecenia RAISE, ktre odpowiada za wygenerowanie wyjtku. Spowoduje to propagacj wyjtku do miejsca, z ktrego procedura zostaa wywoana. Mona powiedzie,
e nie da si z sekcji obsugi wyjtkw przenie si do tej samej sekcji, wic wyjtek
zgoszony w sekcji obsugi wyjtkw musi zosta obsuony pitro wyej w procedurze wywoujcej.
Bardzo czsto wykorzystujemy przy obsudze wyjtkw dwie wbudowane funkcje
PL/SQL: SQLCODE zwracajc numer wyjtku (bdu), oraz SQLERRM wywietlajc zwizany z tym bdem (wyjtkiem) komunikat. Sposb ich zastosowania ilustruje
nastpny przykad.

Cz II ORACLE PL/SQL

176
CREATE OR REPLACE PROCEDURE licz
(mini NUMBER, ile out INT)
IS
brakuje EXCEPTION;
BEGIN
SELECT COUNT(IdOsoby) INTO ile FROM Osoby
WHERE Wzrost > mini;
IF (ile = 0) THEN
RAISE brakuje;
END IF;
EXCEPTION
WHEN brakuje THEN
DBMS_OUTPUT.PUT_LINE('Nie ma takich');
DBMS_OUTPUT.PUT_LINE('kod - ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('opis - ' || SQLERRM);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;

Niestety, w tym miejscu czeka na programist niemia niespodzianka. Wszystkie wyjtki


zdefiniowane przez uytkownika maj taki sam numer (1) oraz komunikat (Wyjtek
uytkownika). Mog przez to sta si nierozrnialne, jeli w procedurze bdzie ich
wicej ni jeden. W takim przypadku moemy zainicjowa wyjtek uytkownika wyjtkiem systemowym, stosujc dyrektyw PRAGMA EXCEPTION_INIT. Posiada ona dwa parametry: pierwszym jest nazwa inicjowanego bdu uytkownika, a drugim reprezentujcy go numer bdu systemowego. Od tej chwili bd uytkownika bdzie przejmowa
po bdzie systemowym jego atrybuty: numer i komunikat.
CREATE OR REPLACE PROCEDURE licz
(mini NUMBER, ile out INT)
IS
brakuje EXCEPTION;
PRAGMA EXCEPTION_INIT(brakuje,-13467);
BEGIN
SELECT COUNT(IdOsoby) INTO ile FROM Osoby
WHERE Wzrost > mini;
IF (ile = 0) THEN
RAISE brakuje;
END IF;
EXCEPTION
WHEN brakuje THEN
DBMS_OUTPUT.PUT_LINE('Nie ma takich');
DBMS_OUTPUT.PUT_LINE('kod - ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('opis - ' || SQLERRM);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;

Takie rozwizanie ma t wad, e musimy dopasowywa komunikat systemowy do wasnych potrzeb, co nie zawsze jest atwe. Pozostaje wic zrezygnowa z definiowania bdu
uytkownika na rzecz stosowania bezporednio polecenia RAISE_APPLICATION_ERROR
lub opisanej poprzednio procedury Blad, ktra to polecenie zawiera wtedy obsuga
nastpi w sekcji OTHERS. Moliwe jest rwnie korzystanie przy obsudze bdu uytkownika z polecenia RAISE_APPLICATION_ERROR w sekcji obsugi wyjtkw.

Rozdzia 7. Procedury skadowane

177

CREATE OR REPLACE PROCEDURE licz


(mini NUMBER, ile out INT)
IS
brakuje EXCEPTION;
BEGIN
SELECT COUNT(IdOsoby) INTO ile FROM Osoby
WHERE Wzrost > mini;
IF (ile = 0) THEN
RAISE brakuje;
END IF;
EXCEPTION
WHEN brakuje THEN
RAISE_APPLICATION_ERROR (-20001, 'Nie ma takich');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;

Wymuszenie wystpienia bdu ad hoc w sekcji obsugi wyjtkw spowoduje jednak


jego propagacj do miejsca wywoania i wtedy powinnimy umieci, np. w bloku
anonimowym, sekcj obsugi wyjtkw obsugujc taki przypadek choby na poziomie zdarzenia OTHERS.
SET SERVEROUTPUT ON;
DECLARE ile NUMBER;
BEGIN
licz(1.8, ile);
DBMS_OUTPUT.PUT_LINE (ile);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;

Z czasem, kiedy bdziemy tworzyli coraz bardziej skomplikowane elementy proceduralne PL/SQL (procedury, funkcje), coraz wiksze bdzie ryzyko, e podczas ich generowania popenimy bdy formalne, skadniowe. Standardowo, jeli w procedurze
znajd si takie bdy, otrzymamy komunikat: Procedura utworzona z bdami kompilacji. Jeli chcemy otrzyma bardziej zoon informacj o popenionych podczas
tworzenia ostatniego elementu proceduralnego bdach, moemy wykona polecenie:
SHOW ERRORS;

Pomimo e wygenerowana w ten sposb informacja jest zdecydowanie bardziej szczegowa, naley z duym dystansem podchodzi do wskazywanych linii kodu, w ktrych
wykryto nieprawidowoci. Bardzo czsto wskazanie to wynika z wczeniej popenionych bdw. Prostym wnioskiem jest ten, e procedur powinnimy poprawia, poczwszy od bdw najwczeniej wykrytych, co w wikszoci przypadkw daje poprawne rezultaty.

You might also like