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;