Kursory Każde zapytanie SQL umieszczone w programie PL/SQL

Transkrypt

Kursory Każde zapytanie SQL umieszczone w programie PL/SQL
Kursory
Każde zapytanie SQL umieszczone w programie PL/SQL jest wykonywane w tzw.
obszarze roboczym lub inaczej obszarze kontekstu. PL/SQL wykorzystuje ten obszar
do
przechowywania
danych
otrzymanych
w
wyniku
zapytania
oraz
do
przechowywania dodatkowych informacji dotyczących stanu wykonywanego
zapytania, tzw. atrybutów. Kursor (ang. cursor) jest konstruktorem PL/SQL
umożliwiającym:
• nadanie nazwy temu obszarowi,
• dostęp do niego,
• pobranie z niego danych,
• kontrolę procesu przetwarzania danych.
Wyróżniamy dwa rodzaje kursorów:
• jawne (ang. explicit) - stosowane w zapytaniach wyznaczających wiele krotek
i w tzw. pętlach z kursorem (ang. Cursor For Loop),
• niejawne (ang. implicit) - stosowane w pozostałych poleceniach SQL (tj.,
insert, update, delete) i poleceniu select wyznaczającym jedną krotkę.
Deklarowanie kursora.
CURSOR nazwa [ ( param1 typ1 [,param2 typ2] ... ) ]
[RETURN typ zwracany]
IS zapytanie SQL;
Jeśli w klauzuli WHERE w deklaracji kursora występują odwołania do zmiennych
PL/SQL (o takich zmiennych mówimy, że są zmiennymi dowiązanymi), to zmienne te
muszą być widoczne w miejscu deklaracji kursora, czyli muszą być zadeklarowane
przed deklaracją kursora.
Kursory jawne
Przed użyciem kursora jawnego należy go najpierw zadeklarować poleceniem
declare:
Przykład 1
declare /* deklaracja kursora */
cursor osoba_kursor is select nazwisko, nazwa from pracownik, zespol
where pracownik.id_zesp = zespol.id_zesp
and zespol.nazwa = 'BAZY DANYCH';
Otwarcie kursora
open nazwa_kursora;
Po otwarciu kursora następuje:
– Sprawdzenie wartości zmiennych dowiązanych,
– Określenie
zbioru
wyników
na
podstawie
wartości
zmiennych
dowiązanych,
– Ustawienie wskaźnika zbioru wynikowego na pierwszym wierszu.
Przykład 2
declare
n zespol.nazwa%type;
cursor osoba_kursor is select nazwisko, nazwa from pracownik, zespol
where pracownik.id_zesp = zespol.id_zesp
and zespol.nazwa = n;
begin
n = 'BAZY DANYCH';
open osoba_kursor;
…... …... …
W momencie otwarcia kursora zmienna n ma wartość 'BAZY DANYCH' i ta wartość
zostaje użyta w zapytaniu. Zmiana wartości zmiennej po wykonaniu instrukcji OPEN
nie zmieni zbioru wynikowego zapytania. To zjawisko nazywamy spójnością
odczytu. Aby w zapytaniu uwzględniona została nowa wartość zmiennej należy
kursor zamknąć i ponownie go otworzyć. Zbiór wynikowy lub zbiór wierszy jest
określany w momencie otwierania kursora. Wówczas ustalany jest również wskaźnik
pokazujący wiersz, który ma być pobrany przez kursor jako następny. UWAGA: Nie
można otworzyć wcześniej otwartego kursora.
Pobranie danych z kursora
fetch nazwa_kursora into lista_zmiennych;
lub
fetch nazwa_kursora into rekord_PL/SQL;
UWAGA: lista_zmiennych oraz pola rekordu muszą być zgodne pod względem typu
z listą wyboru zapytania.
Przykład 3
declare
cursor pracownik_kursor is
select nazwisko, placa_pod, id_zesp from pracownik;
osoba_nazwisko pracownik.nazwisko%TYPE;
osoba_płaca pracownik.placa_pod%TYPE;
osoba_id_zesp pracownik.id_zesp%TYPE;
pracownik_dane pracownik_kursor%ROWTYPE;
begin
open pracownik_kursor;
fetch pracownik_kursor into
osoba_nazwisko, osoba_płaca,
osoba_id_zesp;
fetch pracownik_kursor into pracownik_dane;
……………
Polecenie fetch pobiera pojedynczy wiersz, a wskaźnik zbioru wynikowego zwiększa
wartość odpowiednio dla następnego wiersza. W celu pobrania większej liczby
wierszy jest konieczne wielokrotne użycie polecenia fetch (np. w pętli).
Zamknięcie kursora
close nazwa_kursora;
Po pobraniu wszystkich wierszy ze zbioru wynikowego należy zamknąć kursor. Do
mechanizmu PL/SQL wysyłane są informacje, że przetwarzanie kursora zakończyło
się i zasoby z tym związane (pamięć przydzielona dla zbioru wynikowego oraz
tymczasowa przestrzeń wykorzystywana do wyznaczania tego zbioru) mogą być
zwolnione. UWAGA: Nieprawidłowe jest zamykanie zamkniętego już kursora.
Przykład 4
declare
cursor pracownik_kursor is
select nazwisko, placa_pod, id_zesp from pracownik;
osoba_nazwisko pracownik.nazwisko%TYPE;
osoba_płaca pracownik.placa_pod%TYPE;
osoba_id_zesp pracownik.id_zesp%TYPE;
pracownik_dane pracownik_kursor%ROWTYPE;
begin
open pracownik_kursor;
fetch pracownik_kursor into
osoba_nazwisko, osoba_płaca,
osoba_id_zesp;
fetch pracownik_kursor into pracownik_dane;
close pracownik_kursor;
end;
/
Do kursora można przekazać parametry, jego deklaracja jest wtedy następująca:
declare
cursor nazwa_kursora (param_1 typ_1, ..., param_n typ_n) is …
param_1 typ_1, ..., param_n typ_n oznaczają parametry kursora oraz ich typy. Typy
parametrów są takie same jak typy zmiennych.
Przykład 5
DECLARE
-- Deklarujemy kursor z dwoma parametrami
CURSOR osoba (n pracownik.nazwisko%TYPE, e pracownik.etat%TYPE)
IS
SELECT nazwisko, etat
FROM pracownik p
WHERE UPPER(p.nazwisko)= UPPER(n) AND UPPER(p.etat) =
UPPER(e)
ORDER BY 1 DESC;
zm_osoba osoba%ROWTYPE;
BEGIN
-- Otwarcie kursora. Wielkość liter w łańcuchu bez znaczenia.
OPEN osoba('maleja','ADIUNKT');
LOOP
FETCH osoba INTO zm_osoba;
EXIT WHEN osoba%NOTFOUND;
DBMS_OUTPUT.PUT_LINE
zm_osoba.nazwisko||' '||
END LOOP;
CLOSE osoba;
END;
/
(osoba%ROWCOUNT
||'.
zm_osoba.etat);
'||
Z każdym kursorem są związane cztery atrybuty, w których jest przechowywana
informacja o przebiegu operacji wykonywanych przez kursor.
%NOTFOUND: przyjmuje wartość true jeśli ostatnie polecenie fetch nie
wyznaczyło krotki spełniającej warunek selekcji; w przeciwnym przypadku
przyjmuje wartość false. W poniższym przykładzie, jeśli kursor nie wyznaczy krotki,
atrybut osoba_kursor%NOTFOUND przyjmie wartość true i nastąpi wyjście z pętli.
loop
fetch osoba_kursor into osoba_nazwisko, osoba_nazwa;
exit when osoba_kursor%NOTFOUND;
………………
end loop;
%FOUND: przyjmuje wartość true jeśli ostatnie polecenie fetch wyznaczyło krotkę
spełniającą warunek selekcji; w przeciwnym przypadku przyjmuje wartość false;
%ROWCOUNT: wyznacza liczbę krotek pobranych poleceniem fetch;
loop
fetch osoba_kursor into osoba_nazwisko, osoba_nazwa;
if osoba_kursor%ROWCOUNT > 10 then
…………………
/* odczytano ponad 10 krotek */
end loop;
%ISOPEN: przyjmuje wartość true jeśli kursor jest otwarty, w przeciwnym
przypadku przyjmuje wartość false:
if osoba_kursor%ISOPEN then
/* pobierz krotkę */
fetch osoba_kursor into osoba_nazwisko, osoba_nazwa;
else /*otwórz kursor */
open osoba_kursor;
end if;
Przykład 6
Kursor jawny – pobieranie danych z więcej niż jednego wiersza w pętli FOR.
DECLARE
CURSOR c_emp IS
SELECT *
FROM zespol
ORDER BY nazwa;
BEGIN
FOR uv_emp IN c_emp
LOOP
DBMS_OUTPUT.PUT_LINE(uv_emp.id_zesp||' '||uv_emp.nazwa||' '||
uv_emp.adres);
END LOOP;
END;
/
Komentarz: Zmienna użyta w pętli FOR nie musi być zadeklarowana. PL/SQL
niejawnie deklaruje zmienną, której zasięg jest ograniczony do instrukcji pętli.
Można więc pominąć jawne deklarowanie zmiennej rekordowej. Można też
POMINĄĆ instrukcje OPEN, CLOSE i FETCH.
Przykład 7 Kursor jawny – pomijanie deklaracji kursora.
BEGIN
FOR uv_emp IN ( SELECT * FROM zespol ORDER BY nazwa)
LOOP
DBMS_OUTPUT.PUT_LINE(uv_emp.id_zesp||' '||uv_emp.nazwa||' '||
uv_emp.adres);
END LOOP;
END;
/
Komentarz: W tej konstrukcji można pominąć deklarację kursora oraz instrukcje
OPEN, FETCH i CLOSE.
UWAGA: Zwięzłość kodu nie zawsze jest pożądana. Przykładowo nie można
ponownie wykorzystywać kursora. Czasami lepiej mieć wszystkie instrukcje SELECT
w sekcji DECLARE – przy dłuższych programach ułatwia to jego analizowanie.
Zad.1
Zdefiniować kursor, który zawierać będzie nazwę etatu, nazwę zespołu oraz
nazwisko pracowników zatrudnionych po dacie zatrudnienia pracownika o nazwisku
LECH. Do wypisania zawartości kursora użyć instrukcji OPEN, FETCH i CLOSE.
Zad.2
Zdefiniować kursor, który zawierać będzie roczną średnią płacę pracowników w
poszczególnych grupach etatowych. Wypisać komunikaty DUZO jeśli kwota
odczytana z kursora jest większa od 10000 lub MALO w przeciwnym przypadku.
(Użyj pętli FOR.)
Zad.3
Zdefiniuj kursor zawierający numery tych pracowników, których nazwiska zawierają
na dowolnym miejscu literę podaną jako parametr kursora, wyniki uporządkuj
rosnąco. Zastosuj pętlę FOR do wypisania informacji na ekranie. Parametrem kursora
ma być litera podana przez użytkownika.
Zad.4
Napisz blok, w którym:
– zdefiniuj kursor zawierający niepowtarzające się etaty, na których zatrudnieni są
pracownicy pracujący w zespole o nazwie podanej przez użytkownika;
– wypisz na ekranie sumę płac podstawowych pracowników zatrudnionych na
etatach występujących w kursorze;
– W przypadku gdy kursor jest pusty, wypisz komunikat ZESPOL NIE
ZATRUDNIA PRACOWNIKOW.
Zastosuj pętlę FOR.
Zad.5
Zdefiniuj blok, w którym:
– zdefiniuj kursor k1 zawierający nie powtarzającą się datę zatrudnienia
„najmłodszego” pracownika na etacie podanym jako parametr przez użytkownika;
– zdefiniuj kursor k2 zawierający numery pracowników mających datę zatrudnienia
późniejszą od daty podanej jako parametr.
– wypisz na ekranie zawartość kursora k2 dla daty znajdującej się w kursorze k1.
(Wykorzystaj polecenia OPEN-FETCH-CLOSE.)
Kursory niejawne
• nie są deklarowane przez programistę,
• polecenia open, fetch, close są wykonywane niejawnie przez system,
• atrybuty przechowujące informacje o przebiegu wykonywanych operacji:
SQL%NOTFOUND, SQL%FOUND, SQL%ROWCOUNT, SQL%ISOPEN.
Ich znaczenie jest takie samo, jak odpowiednich atrybutów kursora jawnego.
Na przykład, wynik usunięcia pracownika o nazwisku Mały może być sprawdzony
przez atrybut kursora niejawnego SQL%NOTFOUND w następujący sposób:
delete from pracownik where nazwisko like 'Maleja';
if SQL%NOTFOUND then ...
/* nie ma osoby o takim nazwisku */
SQL%ROWCOUNT - wyznacza liczbę krotek, na których wykonano ostatnie
polecenie insert, update, delete, np.
update pracownicy set placa_pod = placa_pod * 1.2 where id_zesp = 10;
if SQL%ROWCOUNT > 10 then ...
/* uaktualniono więcej niż 10 wierszy */
elsif SQL%ROWCOUNT = 0 then ...
/* żaden wiersz nie spełnia warunku instrukcji update można np.
wstawić nowy wiersz*/
end if;
SZBD automatycznie zamyka niejawny kursor po wykonaniu polecenia, co
oznacza, że wartością atrybutu SQL%ISOPEN jest zawsze false.
Przykład 8
Kursor niejawny – pobieranie danych z jednego wiersza.
DECLARE
uv_nazwisko VARCHAR2(25);
uv_etat VARCHAR2(25);
BEGIN
SELECT nazwisko, etat
INTO uv_nazwisko, uv_etat
FROM pracownik
WHERE numer = 1100;
DBMS_OUTPUT.PUT_LINE('nazwisko: '||uv_nazwisko||', etat: '||uv_etat);
END;
/
Przykład 9
DECLARE
uv_nazwisko pracownik.nazwisko%TYPE;
uv_etat pracownik.etat%TYPE;
BEGIN
SELECT nazwisko, etat
INTO uv_nazwisko, uv_etat
FROM pracownik
WHERE numer = 1100;
DBMS_OUTPUT.PUT_LINE('nazwisko: '||uv_nazwisko||', etat: '||uv_etat);
END;
/
Przykład 10
DECLARE
uv_nazwisko pracownik.nazwisko%TYPE;
uv_etat pracownik.etat%TYPE;
ile PLS_INTEGER;
BEGIN
SELECT nazwisko, etat
INTO uv_nazwisko, uv_etat
FROM pracownik
WHERE numer = 1100;
DBMS_OUTPUT.PUT_LINE('nazwisko: '||uv_nazwisko||', etat: '||uv_etat);
EXCEPTION
/* występuje tylko dla instrukcji SELECT */
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Zapytanie nie zwrocilo danych.');
WHEN TOO_MANY_ROWS THEN
SELECT COUNT(*) INTO ile FROM pracownik WHERE numer = 1100;
DBMS_OUTPUT.PUT_LINE('Zapytanie zwrocilo ' || ile || ' rekordow.');
END;
/
Kursory z klauzulą FOR UPDATE instrukcji SELECT
W celu modyfikowania wierszy pobieranych przez kursor język PL/SQL dostarcza
klauzuli FOR UPDATE w deklaracji kursora oraz klauzuli WHERE CURRENT OF
w instrukcji UPDATE lub DELETE.
Klauzula FOR UPDATE występuje jako ostatnia (za ORDER BY) klauzula w
poleceniu SELECT.
SELECT … FROM … FOR UPDATE [OF odnosnik_do_kolumny] [NOWAIT],
gdzie odnosnik_do_kolumny jest kolumną tabeli, na której jest wykonywane
zapytanie. Może to być również lista kolumn.
Przykład 11
DECLARE
- - Ten kursor wylistuje dwie kolumny dla klauzuli UPDATE
CURSOR wszyscy_pracownicy IS
SELECT *
FROM pracownik
FOR UPDATE OF nazwisko, placa_podst;
- - Ten kursor nie wylistuje żadnej kolumny
CURSOR duza_placa IS
SELECT numer, placa_podst
FROM pracownik
WHERE placa_podst > 2500
FOR UPDATE;
Zmienne kursora
Przestawione powyżej przykłady kursorów jawnych są przykładami kursorów
statycznych - kursor jest związany z jedną instrukcją SQL i ta instrukcja jest znana w
momencie kompilacji bloku. Zmienna kursora może być skojarzona z różnymi
instrukcjami w czasie wykonywania kodu. Przed użyciem zmienna kursora musi być
zadeklarowana. W czasie wykonania dla zmiennej kursora musi być przydzielona
pamięć (typ FER). Następnie kursor jest otwierany, są z niego pobierane dane i jest
zamykany (podobnie jak miało to miejsce z kursorem statycznym). Zmienne kursora
są najczęściej wykorzystywane wewnątrz procedur składowanych, które zwracają
zmienne do programu działającego po stronie klienta.
Zmienna kursora jest typem odwołania (jak wskaźniki w C). Może określać różne
miejsca pamięci
w czasie wykonywania programu.
Deklaracja typu odwołania:
REF typ,
gdzie typ jest uprzednio zdefiniowanym typem. Słowo kluczowe REF wskazuje, że
nowy typ będzie wskaźnikiem do zdefiniowanego typu.
TYPE nazwa_typu IS REF CURSOR RETURN typ_rekordu;
gdzie nazwa_typu jest nazwą nowego typu odwołania, a typ_rekordu jest typem
rekordu wskazującego typy z listy wyboru, które będą ewentualnie zwrócone przez
zmienną kursora. Zwracany typ zmiennej kursora musi być typem rekordu
zadeklarowanym jawnie jako rekord zdefiniowany przez użytkownika lub niejawnie
%ROWTYPE.
Przykład 12
DECLARE
TYPE t_pracownik IS REF CURSOR RETURN pracownik%ROWTYPE;
TYPE t_rekord IS RECORD (
numer pracownik.numer%TYPE,
nazwisko pracownik.nazwisko%TYPE
);
zm_t_rekord t_rekord;
TYPE t_numer_nazwisko IS REF CURSOR RETURN t_rekord;
TYPE t_numer_nazwisko_2 IS REF CURSOR
RETURN zm_t_rekord%TYPE;
zm_t_pracownik t_pracownik;
zm_t_numer_nazwisko t_numer_nazwisko;
Przykład 12 zawiera ograniczone zmienne kursora – deklarowane tylko dla
określonego typu zwracanych informacji. W deklaracji nieograniczonych zmiennych
kursora nie ma klauzuli RETURN. Stąd mogą być otwarte dla dowolnego zapytania.
Przykład 13
DECLARE
TYPE t_pracownik IS REF CURSOR;
zm_t_pracownik t_pracownik;
Otwieranie zmiennej kursora dla zapytania
OPEN zmienna_kursora FOR instrukcja_wyboru;
UWAGA: Jeżeli zmienna kursora jest ograniczona, to lista wyboru musi
odpowiadać typowi wyniku kursora.
W zapytaniu sprawdzane są zmienne dowiązane i określany jest zbiór wynikowy. Z
otwartej zmiennej kursora można pobierać dane instrukcją FETCH, a następnie
zmienną kursową można zamknąć.
Zamykanie zmiennej kursora
CLOSE zmienna_kursora;
Instrukcja CLOSE zwalnia zasoby użyte dla zapytania, ale niekoniecznie zwalnia
obszar pamięci dla samej zmiennej kursora. Obszar pamięci zmiennej zwalniany jest
wtedy, kiedy zmienna wychodzi poza zakres. Zamykanie kursora lub zmiennej
kursora, które są już zamknięte, jest nieprawidłowe.
Przykład 14
DECLARE
TYPE t_pracownik IS REF CURSOR;
zm_t_pracownik t_pracownik;
zm_numer pracownik.numer%TYPE;
zm_nazwisko pracownik.nazwisko%TYPE;
BEGIN
OPEN zm_t_pracownik FOR SELECT numer, nazwisko FROM pracownik;
LOOP
FETCH zm_t_pracownik INTO zm_numer, zm_nazwisko;
EXIT WHEN zm_t_pracownik%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(zm_t_pracownik%ROWCOUNT || ' ' ||
zm_numer || ' ' || zm_nazwisko);
END LOOP;
CLOSE zm_t_pracownik;
END;
/
UWAGI:
• Zmienne kursora nie mogą być deklarowane w pakiecie; można w nim
deklarować tylko typy.
• Zdalne procedury nie mogą zwracać wartości zmiennej kursora.
Zmienne kursora mogą być przekazywane pomiędzy mechanizmem
PL/SQL po stronie klienta oraz po stronie serwera, ale nie pomiędzy
dwoma serwerami.
• Kolekcje języka PL/SQL (tabele indeksowe, tabele zagnieżdżone oraz
tablice VARRAY) nie mogą zawierać zmiennej kursora. Podobnie tabele
bazy danych i perspektywy nie mogą zawierać kolumn typu REF
CURSOR. Można natomiast zdefiniować tablicę zmiennych kursora po
stronie klienta.
• Nie można używać zmiennych kursora z dynamicznym SQL w
programie Pro*C.
• Zapytanie skojarzone ze zmienną kursora w instrukcji OPEN … FOR …
nie może wykorzystywać klauzuli FOR UPDATE. Ograniczenie
zniesione od wersji Oracle8i.
Wyjątek (ang. exception)
• jest szczególnym zdarzeniem, które może zajść w trakcie wykonywania
programu, np. dzielenie przez zero;
• może być obsłużony przez związaną z nim procedurę nazywaną
procedurą obsługi wyjątku (ang. exception handling);
• w każdym programie mogą zostać wywołane dwa rodzaje wyjątków:
• predefiniowane, wywoływane niejawnie przez system w trakcie
działania programu lub wywoływane jawnie przez programistę;
• definiowane przez użytkownika, wywoływane jawnie w ciele
programu odpowiednim poleceniem.
Aby wywołać wyjątek definiowany należy go najpierw zadeklarować w sekcji
deklaracji bloku:
DECLARE
brak_danych EXCEPTION;
Z każdym wyjątkiem (predefiniowanym i definiowanym) musi być związana
procedura obsługi wyjątku, którą definiujemy w ostatnim bloku lub podbloku
programu, oddzielonym od pozostałych bloków słowem kluczowym EXCEPTION:
EXCEPTION
/* początek bloku definiowania wyjątków */
WHEN brak_danych
THEN /*jeśli wywołany wyjątek brak_danych */
INSERT INTO pracownicy VALUES (...);
UWAGA: Jeśli chcemy aby ta sama procedura obsługi wyjątku ma być wykonywana
dla różnych wyjątków, w klauzuli WHEN należy nazwy wyjątków oddzielić od siebie
słowem kluczowym OR.
Procedura obsługi wyjątków predefiniowanych jest wywoływana niejawnie w trakcie
działania programu, może być również wywołana jawnie w ciele programu.
Przykładowo, próba zamknięcia kursora, który nie został wcześniej otwarty
spowoduje wywołanie wyjątku niejawnego, którego procedurę obsługi umieszczono
po słowie kluczowym exception.
Przykład 15
declare
cursor pracownik_kursor is
select numer, nazwisko, placa_pod from pracownik;
pracownik_rekord pracownik_kursor%ROWTYPE;
begin
close pracownik_kursor;
/* zamknięcie kursora, który nie został wcześniej otwarty */
exception
when INVALID_CURSOR then null;
end;
/
Wyjątek i związaną z nim procedurę obsługi wywołujemy jawnie poleceniem raise.
select count(*) into liczba_prac
from pracownicy;
if liczba_prac = 0 then raise brak_danych;
Wybrane predefiniowane wyjątki:
DUP_VAL_ON_INDEX - wywoływany, gdy na skutek wykonania polecenia insert
lub update różne rekordy relacji posiadają tę samą wartość atrybutu zadeklarowanego
jako unikalny;
INVALID_CURSOR - wywoływany w wyniku wykonania operacji na kursorze,
która jest niepoprawna w pewnym kontekście, np. Zamknięcie nieotwartego kursora;
INVALID_NUMBER - wywoływany, gdy nie jest możliwa konwersja łańcucha
znaków do postaci liczby, ponieważ łańcuch zawiera niedopuszczalne wartości;
LOGIN_DENIED - wywoływany w przypadku podania niepoprawnych parametrów
w poleceniu rozpoczęcia sesji - login, np. nazwy użytkownika lub hasła;
NO_DATA_FOUND - wywoływany, gdy polecenie select nie wyznacza żadnej
krotki;
NOT_LOGGED_ON - wywoływany w wyniku próby wykonania funkcji Oracle
przez użytkownika nie dołączonego do systemu;
PROGRAM_ERROR - wywoływany w wyniku błędnego działania programu
PL/SQL;
STORAGE_ERROR - wywoływany w wyniku błędu pamięci lub braku miejsca w
pamięci;
TIMEOUT_ON_RESOURCE - wywoływany po upłynięciu czasu oczekiwania na
przydzielenie zasobu;
TOO_MANY_ROWS - wywoływany, gdy jest wymagana dokładnie jedna krotka, a
polecenie select wyznacza większą liczbę krotek;
VALUE_ERROR - wywoływany w przypadku błędu konwersji typów danych (np.
próby wpisania daty do numerycznego pola krotki) lub, gdy aktualna długość danej
przekracza wcześniej zadeklarowaną długość (np. próba wpisania do pola krotki o
długości 3 znaków danej o długości 5 znaków);
ZERO_DIVIDE - wywoływany w wyniku próby dzielenia przez 0;
OTHERS - wywoływany w dla wszystkich wyjątków, które nie zostały
wyspecyfikowane w bloku exception; definiowany jako ostatni w bloku exception.
Do uzyskania informacji o błędzie można uzyskać dzięki funkcjom:
• SQLCODE – zwraca bieżący kod błędu, dla wyjątków zdefiniowanych
przez użytkownika zwraca 1;
• SQLERRM – zwraca tekst komunikatu o bieżącym błędzie, dla
wyjątków zdefiniowanych przez użytkownika zwraca komunikat „Userdefined
Exception”.
Może
być
wywoływana
z
pojedynczym
argumentem liczbowym:
▪ 0 – normalne, udane zakończenie;
▪ > 0 i <> +100 – wyjątek nie jest wyjątkiem systemowym Oracle;
▪ < 0 zwraca komunikat skojarzony z błędem;
▪ bez argumentu – zwraca zawsze normalne, udane zakończenie.
Wyżej wymienione funkcje przypisywane są zmiennym lokalnym, które
następnie
stosowane są w instrukcjach SQL.
Zad.6
Zdefiniuj kursor zawierający nazwiska i daty zatrudnienia wszystkich asystentów.
Posłuż się tym kursorem do wyświetlenia rekordów w formie zdań „Asystent
<nazwisko> pracuje od <data_zatrudnienia>”. Posłuż się poleceniem FETCH.
Kolekcje
Tablice indeksowane:
TYPE nazwa_typu IS TABLE OF typ INDEX BY BINARY_INTEGER;
Tablice indeksowane dla typów nieskalarnych:
•
rekordy
TYPE nazwa_typu IS TABLE OF typ_rekord INDEX BY BINARY_INTEGER;
Przykład 16
DECLARE
TYPE t_etat IS TABLE OF etat%ROWTYPE
INDEX BY BINARY_INTEGER;
zm_t_etat t_etat;
BEGIN
SELECT * INTO zm_t_etat(1000)
FROM etat
WHERE nazwa = 'profesor';
DBMS_OUTPUT.PUT_LINE(zm_t_etat(1000).nazwa);
zm_t_etat(1001) := 'audytor';
DBMS_OUTPUT.PUT_LINE(zm_t_etat(1001).nazwa);
END;
/
•
obiekty
Zaczynamy od utworzenia typu obiektowego, a następnie można tworzyć
egzemplarze gotowego typu obiektowego.
Przykład 17
CREATE OR REPLACE TYPE Moj_obiekt AS OBJECT(
pole_1 number, pole_2 varchar2(20), pole_3 date);
/
DECLARE
TYPE t_obiektow IS TABLE OF Moj_obiekt
INDEX BY BINARY_INTEGER;
zm_obiektow t_obiektow;
BEGIN
zm_obiektow(1) := Moj_obiekt(1, NULL, NULL);
zm_obiektow(1).pole_1 := 'Norbert';
zm_obiektow(1).pole_2 := sysdate;
DBMS_OUTPUT.PUT_LINE(zm_obiektow(1).pole_1||' '||
zm_obiektow(1).pole_2||' '||zm_obiektow(1).pole_3);|
END;
/
•
tabele zagnieżdżone
◦ Tabele zagnieżdżone można tworzyć używając kluczy sekwencyjnych, a te
nie mogą być liczbami ujemnymi.
◦ Tabele zagnieżdżone można zapisywać w bazie danych.
◦ Maksymalna liczba wierszy w tabeli zagnieżdżonej wynosi 2 GB (to
maksymalna wartość klucza).
Składnia:
TYPE nazwa IS TABLE OF typ_tablicowy [NOT NULL];
gdzie typ_tablicowy może być typem wbudowanym, typem zdefiniowanym przez
użytkownika lub wyrażeniem zawierającym %TYPE, ale nie może być to jeden z
typów: BOOLEAN, NCHAR, NVARCHAR2 lub REF CURSOR.
Gdy występuje fraza NOT NULL, elementy tabeli zagnieżdżonej nie mogą
przyjmować wartości NULL.
Przykład 18
DECLARE
TYPE tabObiektow IS TABLE OF Moj_obiekt;
zm_obiektow tabObiektow := tabObiektow(Moj_obiekt(1,'ala',sysdate));
BEGIN
DBMS_OUTPUT.PUT_LINE(zm_obiektow(1).pole_1);
END;
/
Metody kolekcji (tabele zagnieżdżone)
Metoda
Typ zwracanej
wartości
Opis
Poprawne dla
EXISTS
BOOLEAN
Sprawdza istnienie danego Tabele indeksowane,
elementu kolekcji.
tabele zagnieżdżone.
COUNT
NUMBER
Zwraca liczbę elementów Tabele indeksowane,
w kolekcji.
tabele zagnieżdżone.
LIMIT
NUMBER
Zwraca maksymalną
liczbę elementów w
kolekcji.
FIRST
(LAST)
BINARY_INTEGER Zwraca pierwszy (ostatni) Tabele indeksowane,
element kolekcji.
tabele zagnieżdżone.
Tabele zagnieżdżone
(zawsze
zwraca
NULL).
NEXT
BINARY_INTEGER Zwraca następny
(PRIOR)
(poprzedni) element
kolekcji względem
danego.
Tabele indeksowane,
tabele zagnieżdżone.
EXTEND N/A
Dodaje element do
kolekcji.
Tabele zagnieżdżone.
TRIM
Usuwa element z końca
kolekcji.
Tabele zagnieżdżone
N/A
DELETE N/A
Usuwa wybrane elementy Tabele indeksowane,
kolekcji.
tabele zagnieżdżone.

Podobne dokumenty