
Strona o szybkim czytaniu.
Podstawową jednostką języka PL/SQL jest blok.
Blok PL/SQL przed wykonaniem musi zostać skompilowany, nie kompiluje się jednak do postaci wykonalnej (.exe, .dll, .lib), którą można uruchomić z poziomu systemu operacyjnego.
W PL/SQL nie można bezpośrednio używać żadnych instrukcji DDL.
Każdy blok PL/SQL może zawierać trzy sekcje:
DECLARE
/* Sekcja deklaracyjna */
BEGIN
/* Sekcja wykonywalna */
EXCEPTION
/* Sekcja obsługi błędów */
END;
Sekcja deklaracyjna i sekcja obsługi wyjątków są opcjonalne, zatem najprostszy blok PL/SQL może wyglądać w następujący sposób:
BEGIN
/* Sekcja wykonywalna */
END;
BEGIN
INSERT INTO grupy_cen VALUES (30, 10000, 30000);
END;
Bloki PL/SQL mogą być w sobie zagnieżdżane.
W PL/SQL istnieją trzy podstawowe rodzaje bloków.
Nie są przechowywane na serwerze bazy danych ani w postaci kodu, ani w postaci skompilowanej. Przed każdym wykonaniem muszą być kompilowane.
DECLARE
/* Sekcja deklaracyjna */
BEGIN
/* Sekcja wykonywalna */
EXCEPTION
/* Sekcja obsługi błędów */
END;
Procedury i funkcje (podprogramy składowane) są to bloki PL/SQL, które mają swoją nazwę. Są one kompilowane tylko jeden raz podczas tworzenia. Na serwerze bazy danych jest przechowywany zarówno kod procedury, jak i postać skompilowana. Wykonanie procedury lub funkcji nie wymaga ponownej kompilacji.
Do procedur i funkcji mogą być przekazywane parametry. Parametry mogą być również przekazywane z procedur i funkcji do środowiska, które je wywołuje.
CREATE OR REPLACE PROCEDURE procedura1
IS
/* Sekcja deklaracyjna */
BEGIN
/* Sekcja wykonywalna */
EXCEPTION
/* Sekcja obsługi błędów */
END;
Wyzwalacze są to bloki PL/SQL, które nie mogą być wywoływane bezpośrednio poleceniem SQL. Ich wykonanie jest bezpośrednio zależne od zajścia pewnego zdarzenia, z którym zostały powiązane.
Do wyzwalaczy nie można bezpośrednio przekazać parametrów.
Przed wersją 7.3 wyzwalacze były przechowywane w bazie danych tylko w postaci kodu. Od wersji 7.3 włącznie przechowywana jest także postać skompilowana wyzwalaczy, co ma wpływ na wydajność.
CREATE OR REPLACE TRIGGER trigger1
BEFORE INSERT ON tabela1
DECLARE
/* Sekcja deklaracyjna */
BEGIN
/* Sekcja wykonywalna */
EXCEPTION
/* Sekcja obsługi błędów */
END;
W PL/SQL niektóre typy danych są inne niż w SQL:
CHAR(L)
– maksymalna długość wynosi 32768 znaków zamiast 255 w SQLVARCHAR2(L)
– maksymalna długość wynosi 32768 znaków zamiast 4000 w SQLBOOLEAN
– typ, który może przyjmować tylko trzy wartości: TRUE, FALSE, NULL. Nie miał swojego odpowiednika w SQLZmienne są deklarowane w sekcji deklaracyjnej bloku PL/SQL.
Składnia deklaracji zmiennej jest następująca:
nazwa_zmiennej typ_zmiennej [CONSTANT] [NOT NULL] [:= wartość];
Zamiast operatora przypisania może pojawić się słowo DEFAULT
.
Zamiast jawnego podawania typu zmiennej można odwołać się do typu zmiennej wcześniej zadeklarowanej lub do typu kolumny bazodanowej poprzez użycie nazwy tej zmiennej (nazwy kolumny) i operatora %TYPE.
Jeżeli zmienna nie zostanie zainicjowana, to jej wartość wynosi NULL.
Przykład poprawnych deklaracji:
DECLARE
v_1 number(9);
v_2 number CONSTANT := 3.14;
v_3 varchar2(10) := 'Ala';
v_4 v_1%TYPE;
v_5 klienci.imie%TYPE;
v_6 char (4) NOT NULL := 'Ala';
v_7 v_1%TYPE;
BEGIN
...
Przykład niepoprawnych deklaracji:
DECLARE
v_1 number(2) := 123;
v_2,v_3 varchar2(10);
v_4 number(3) NOT NULL;
v_5 varchar2;
BEGIN
...
W PL/SQL zasięg zmiennych, a więc obszar kodu, w którym zachowują swoją wartość rozciąga się od momentu zadeklarowania zmiennej do końca bloku, w którym zmienna ta została zadeklarowana.
Instrukcje DML: INSERT
, UPDATE
i DELETE
w PL/SQL stosuje się podobnie jak w SQL, z tą różnicą, że zamiast podawania wartości stałych można stosować zmienne lub nawet wyrażenia.
DECLARE
v_id_klienta number (9) := 1000;
v_id_komputera number (9) := 340;
v_id_procesora number (9) := 510;
BEGIN
INSERT INTO zamowienia (zam_id, zam_numer, zam_data_zamowienia,
zam_data_realizacji, zam_opis, zam_klt_id)
VALUES (seq_zamowienia.nextval, 200, sysdate, null,
'Nowe zamówienie na komputery', v_id_klienta);
INSERT INTO pozycje_zamowien(pzm_id, pzm_lp, pzm_ilosc,
pzm_zam_id, pzm_tow_id)
VALUES (seq_pozycje_zamowien.nextval, 1, 1,
seq_zamowienia.currval, v_id_komputera);
INSERT INTO pozycje_zamowien(pzm_id, pzm_lp, pzm_ilosc,
pzm_zam_id, pzm_tow_id)
VALUES (seq_pozycje_zamowien.nextval, 2, 5,
seq_zamowienia.currval, v_id_procesora);
COMMIT;
END;
Inaczej jest w przypadku instrukcji SELECT
. Jeżeli używamy jej w zwykłym SQL, to wynik zwrócony przez tą instrukcję jest wyświetlany na konsoli. W PL/SQL nie ma konsoli, a dane zwrócone przez zapytanie nie powinny zostać pokazane użytkownikowi, ale przetworzone przez kolejne instrukcje kodu. Aby to umożliwić, instrukcja SELECT
w PL/SQL została wzbogacona o kolejną klauzulę, która pozwala przekierować wartości zwrócone przez zapytanie do wskazanych zmiennych.
SELECT kol_1, kol_2, kol_3, ..., kol_n
INTO zmienna_1, zmienna_2, zmienna_3, ..., zmienna_n
FROM tabela
WHERE ...
DECLARE
v_id_klienta number (9);
v_id_komputera number (9);
v_id_procesora number (9);
BEGIN
SELECT klt_id
INTO v_id_klienta
FROM klienci
WHERE klt_imie = 'Jan'
AND klt_nazwisko = 'Kowalski';
INSERT INTO zamowienia (zam_id, zam_numer, zam_data_zamowienia,
zam_data_realizacji, zam_opis, zam_klt_id)
VALUES (seq_zamowienia.nextval, 200, sysdate, null,
'Nowe zamówienie na komputery', v_id_klienta);
SELECT tow_id
INTO v_id_komputera
FROM towary
WHERE tow_nazwa = 'Komputer';
INSERT INTO pozycje_zamowien(pzm_id, pzm_lp, pzm_ilosc,
pzm_zam_id, pzm_tow_id)
VALUES (seq_pozycje_zamowien.nextval, 1, 1,
seq_zamowienia.currval, v_id_komputera);
SELECT tow_id
INTO v_id_procesora
FROM towary
WHERE tow_nazwa = 'Procesor Pentium III 700 MHz';
INSERT INTO pozycje_zamowien(pzm_id, pzm_lp, pzm_ilosc,
pzm_zam_id, pzm_tow_id)
VALUES (seq_pozycje_zamowien.nextval, 2, 5,
seq_zamowienia.currval, v_id_procesora);
COMMIT;
END;
Jeżeli korzystamy z instrukcji SELECT
w PL/SQL, to instrukcja ta MUSI zwracać dokładnie jeden wiersz. Jeżeli zwróci mniej lub więcej, to instrukcja ta kończy się niepowodzeniem.
Instrukcja decyzyjna IF pozwala na selektywne wykonywanie pewnych instrukcji w oparciu o warunek logiczny określony wyrażeniem.
Pełna składnia instrukcji IF:
IF wyrażenie_logiczne1 THEN
ciąg_instrukcji1
ELSIF wyrażenie_logiczne2 THEN
ciąg_instrukcji2
...
ELSIF wyrażenie_logiczne3 THEN
ciąg_instrukcji3
ELSE
ciąg_instrukcji4
END IF;
Klauzule ELSIF
i ELSE
są opcjonalne i jeżeli nie ma takiej potrzeby, mogą zostać pominięte.
Podczas wykonywania instrukcji IF
obliczane jest wyrażenie wyrażenie_logiczne1. Jeżeli jest ono prawdziwe, to wykonywane są instrukcje ciąg_instrukcji1, a następnie sterowanie przechodzi do pierwszej instrukcji po klauzuli END IF
. W przypadku, gdy wyrażenie_logiczne1 jest fałszywe, lub ma wartość NULL
, obliczane są kolejne warunki logiczne, aż któryś z nich okaże się prawdziwy. Jeżeli żaden z nich nie będzie prawdziwy, wykonywane są instrukcje następujące po klauzuli ELSE (ciąg_instrukcji4)
.
IF
może zakończyć się trudnym do wykrycia błędem w przypadku, gdy nie pamięta się o możliwości wystąpienia wartości NULL
. Poniżej, po prawej i lewej stronie, wbrew pozorom, nie znajduje się kod równoważny.
DECLARE
v1 number;
v2 number;
v3 varchar2(100);
BEGIN
... ...
IF v1 > v2 THEN IF v1 <= v2 THEN
v3 := 'v1 większe'; v3 := 'v1 mniejsze, równe';
ELSE ELSE
v3 := 'v1 mniejsze, równe'; v3 := 'v1 większe';
END IF; END IF;
... ...
END;
Najprostsza pętla składa się z ciała instrukcji, które mają być powtarzane, zamkniętego między ogranicznikami.
LOOP i END LOOP.
LOOP
ciąg_instrukcji
END LOOP;
Za każdym razem, gdy wykonanie osiągnie instrukcję END LOOP
sterowanie jest przekazywane z powrotem do instrukcji poprzedzonej przez klauzulę LOOP
.
Aby wyjść z takiej pętli należy wykonać instrukcję EXIT
, która powoduje natychmiastowe opuszczenie pętli (bez wykonania się bieżącego cyklu). Jeżeli do instrukcji EXIT
dodamy klauzulę WHEN
wraz z odpowiednim warunkiem, to pętla zostanie opuszczona tylko w przypadku prawdziwości tego warunku;
EXIT [WHEN warunek];
DECLARE
v1 binary_integer;
BEGIN
v1 := 0;
LOOP
v1 := v1 + 1;
EXIT WHEN v1 > 50;
INSERT INTO grupy_cen
VALUES (30, 100000, 500000);
END LOOP;
END;
Pętla WHILE
jest nieco zmodyfikowaną pętlą LOOP
. Do zakończenia nie wymaga ona wpisania instrukcji EXIT
, chociaż instrukcja ta może się w niej pojawić. Warunek wykonywania się pętli jest określany w jej nagłówku po słowie WHILE
.
WHILE warunek_logiczny LOOP
ciąg_instrukcji
END LOOP;
Pętla wykonuje się cyklicznie, dopóki warunek warunek_logiczny
jest prawdziwy.
grupy_cen
50 wierszy.
DECLARE
v1 binary_integer;
BEGIN
v1 := 0;
WHILE v1 < 50 LOOP
v1 := v1 + 1;
INSERT INTO grupy_cen VALUES (30, 100000, 500000);
END LOOP;
END;
Pętla FOR
posiada dodatkowo przed słowem kluczowym LOOP
frazę sterującą określającą liczbę iteracji do wykonania.
Składnia pętli FOR:
FOR zmienna IN [REVERSE] zakres_dolny..zakres_górny LOOP
ciąg_instrukcji
END LOOP;
Podczas każdej kolejnej iteracji zmienna sterująca pętli FOR
przybiera kolejną wartość z zakresu określonego przez zakres_dolny
i zakres_górny
.
Jeżeli użyjemy słowa REVERSE
, to zmienna sterująca będzie przybierać wartości z określonego zakresu malejąco.
Zmienna sterująca pętlą nie musi być deklarowana, a jej zasięg jest tylko w zakresie pętli FOR
, którą steruje.
grupy_cen
50 wierszy.
DECLARE
v1 number;
v2 number;
BEGIN
v1 := 11;
v2 := 60;
FOR v3 IN v1..v2 LOOP –- Pętla wykona się 50 razy
v2 := 15; -- Przypisanie do v2 wartości 15
INSERT INTO grupy_cen
VALUES (30, 100000, 500000);
END LOOP; -- Zmiana wartości v1 i v2 nie ma wpływu na pętlę
END;