PL/SQL Zaawansowane tematy PL/SQL
Cele Poznanie złożonych i referencyjnych typów danych Poznanie konstrukcji kursora Poznanie kodu składowanego Poznanie procedur i funkcji 2
Złożone typy danych RECORD typ danych zawierający wiele wartości skalarnych Deklaracja typu danych: TYPE r_faktura IS RECORD ( kwota NUMBER, dostawca VARCHAR2(100) ); deklaracja zmiennej: l_faktura r_faktura; wykorzystywanie pól zmiennej typu rekord: l_faktura.kwota := 100; 3
Złożone typy danych - przykład DECLARE TYPE r_faktura IS RECORD( kwota NUMBER, dostawca VARCHAR2(100)); lr_faktura1 r_faktura; lr_faktura2 r_faktura; Begin lr_faktura1.kwota := 100; lr_faktura2.kwota := 200; lr_faktura1.dostawca := IBM ; lr_faktura2.kwota := lr_faktura1.kwota + lr_faktura2.kwota; lr_faktura2.dostawca := lr_faktura1.dostawca; lr_faktura1 := lr_faktura2; End; 4
Referencyjne typy danych %TYPE: Typ danych zgodny z typem kolumny w tabeli ls_first_name EMPLOYEES.FIRST_NAME%TYPE; %ROWTYPE: deklaruje zmienne typu RECORD, wartości skalarne są zgodne z definicją tabeli l_employees EMPLOYEES%ROWTYPE; 5
Referencyjne typy danych - przykład DECLARE ls_first_name EMPLOYEES.FIRST_NAME%TYPE; ls_first_name := Jan ; DBMS_OUTPUT.PUT_LINE(ls_first_name); 6
Referencyjne typy danych - przykład DECLARE lr_employee1 EMPLOYEES%ROWTYPE; lr_employee2 EMPLOYEES%ROWTYPE; lr_employee1.first_name:= Jan ; lr_employee1.last_name:= Kowalski ; lr_employee2.first_name:= Andrzej ; lr_employee1.last_name:= lr_employee1.last_name; 7
Referencyjne typy danych - przykład DECLARE lr_employee EMPLOYEES%ROWTYPE; lr_employee.first_name:= Andrzej ; lr_employee.last_name:= Nowak ; lr_employee.salary:= 5000; INSERT INTO EMPLOYEES VALUES lr_employee; 8
Kursory Służą do pobierania danych z bazy danych na podstawie zapytania 9
Niejawny kursor (Implicit Cursor) Uruchomienie zapytania SELECT.. INTO tworzy niejawny kursor Niejawany kursor zwraca wyniki zapytania do zmiennej: SELECT first_name, last_name, salary INTO ls_first_name, ls_last_name, ln_salary FROM employees WHERE employee_id = 100; 10
Niejawny kursor (Implicit Cursor) Może być użyty tylko z zapytaniami zwracającymi jeden rekord Gdy zapytanie zwróci więcej niż jeden rekord, podniesiony zostanie wyjątek TOO_MANY_ROWS Gdy zapytanie nie zwróci danych, podniesiony zostanie wyjątek NO_DATA_FOUND 11
Niejawny kursor przykład DECLARE ls_first_name employees.first_name%type; ls_last_name employees.last_name%type; ln_salary employees.salary%type; SELECT first_name, last_name, salary INTO ls_first_name, ls_last_name, ln_salary FROM employees WHERE employee_id = 100; DBMS_OUTPUT.PUT_LINE(ls_first_name ' ' ls_last_name ' zarabia ' ln_salary); 12
Niejawny kursor przykład DECLARE lr_employee EMPLOYEES%ROWTYPE; SELECT * INTO lr_employee FROM EMPLOYEES WHERE employee_id = 100; DBMS_OUTPUT.PUT_LINE(lr_employee.first_name ' ' lr_employee.last_name ' zarabia ' lr_employee.salary); 13
Kursory jawne (Explicit) Służą do pobierania danych z bazy danych na podstawie zapytania Umożliwiają przetwarzanie danych rekord po rekordzie 14
Kursory Deklaracja kursora (w sekcji deklaracji) CURSOR nazwa_kursora IS zapytanie_select; Otwarcie kursora OPEN nazwa_kursora Pobranie danych FETCH nazwa_kursora INTO zmienne; Zamknięcie kursora CLOSE nazwa_kursora; 15
Przykład wykorzystania kursora DECLARE CURSOR c_kursor_pracownicy IS SELECT FIRST_NAME, LAST_NAME FROM employees; ls_first_name VARCHAR2(100); ls_last_name VARCHAR2(100); OPEN c_kursor_pracownicy; FETCH c_kursor_pracownicy INTO ls_first_name, ls_last_name ; dbms_output.put_line(ls_first_name ls_last_name); FETCH c_kursor_pracownicy INTO ls_first_name, ls_last_name ; dbms_output.put_line(ls_first_name ls_last_name); CLOSE c_kursor_pracownicy; 16
Zapisywanie wyników kursora do zmiennej złożonej Baza Oracle umożliwia stworzenie zmiennej RECORD o polach zgodnych z kursorem. W tym celu należy użyć słowa kluczowego %ROWTYPE: nazwa_kursora CURSOR IS SELECT * from employees; lr_zmienna nazwa_kursora%rowtype; FETCH nazwa_kursora INTO lr_zmienna; DBMS_OUTPUT.PUT_LINE(lr_zmienna.first_name); 17
Zapisywanie wyników kursora do zmiennej złożonej DECLARE CURSOR c_kursor_pracownicy IS SELECT * FROM employees; lr_pracownik c_kursor_pracownicy%rowtype; OPEN c_kursor_pracownicy; FETCH c_kursor_pracownicy INTO lr_pracownik; dbms_output.put_line( Pracownik lr_pracownik.first_name lr_pracownik.last_name pobiera wynagrodzenie lr_pracownik.salary) ; CLOSE c_kursor_pracownicy; 18
Atrybuty kursora Do sprawdzenia statusu kursora służą poniższe atrybuty Atrybut %ISOPEN %FOUND %NOTFOUND %ROWCOUNT Opis Zwraca TRUE gdy kursor jest otwarty, FALSE gdy kursor jest zamknięty Zwraca TRUE gdy kursor zwrócił dane, FALSE gdy kursor nie zwrócił danych (wszystkie dane z zapytania zostały pobrane). Zwraca FALSE gdy kursor zwrócił dane, TRUE gdy kursor nie zwrócił danych (wszystkie dane z zapytania zostały pobrane). Zwraca ilość już pobranych rekordów 19
Stosowanie atrybutów kursora IF c_kursor%isopen THEN dbms_output.put_line( Kursor c_kursor jest otwarty ); END IF; ------------------------------------------------------------------------------------ FETCH c_kursor INTO r_dane; IF c_kursor%notfound THEN dbms_output.put_line( Nie znaleziono danych w kursorze ); END IF; ------------------------------------------------------------------------------------ Dbms_output.put_line( Jak dotąd z kursora pobrano c_kursor%rowcount rekordów ); 20
Stosowanie atrybutów kursora DECLARE CURSOR c_kursor_pracownicy IS SELECT * FROM employees; lr_pracownik c_kursor_pracownicy%rowtype; OPEN c_kursor_pracownicy; FETCH c_kursor_pracownicy INTO lr_pracownik; IF c_kursor_pracownicy%notfound THEN DBMS_OUTPUT.PUT_LINE( Nie znaleziono pracownika! ); CLOSE c_kursor_pracownicy; RETURN; END IF; CLOSE c_kursor_pracownicy; 21
Pobieranie danych z kursora w pętli Deklaracja kursora (w sekcji deklaracji) CURSOR nazwa_kursora IS zapytanie_select; Otwarcie kursora OPEN nazwa_kursora Pobranie danych LOOP FETCH nazwa_kursora INTO zmienne; EXIT WHEN nazwa_kursora%notfound; Zamknięcie kursora CLOSE nazwa_kursora; 22
Pobieranie danych z kursora w pętli DECLARE CURSOR c_kursor_pracownicy IS SELECT FIRST_NAME FROM employees; l_first_name VARCHAR2(100); OPEN c_kursor_pracownicy; LOOP FETCH c_kursor_pracownicy INTO l_first_name; EXIT WHEN c_kursor_pracownicy%notfound; dbms_output.put_line(l_first_name); END LOOP; CLOSE c_kursor_pracownicy; 23
Pobieranie danych z kursora w pętli Aby skrócić zapis pobierania wszystkich rekordów z kursora Oracle wprowadził specjalną konstrukcję pętli FOR przetwarzającą kursory Pętla FOR automatycznie otwiera kursor, pobiera rekordy i zamyka kursor: FOR nazwa_zmiennej IN kursor LOOP instrukcje END LOOP; Zmienne kursorowe nie mogą być wykorzystywane poza pętlą 24
Pobieranie danych z kursora w pętli Przykład wykorzystania konstrukcji pętli FOR przetwarzającej kursor DECLARE CURSOR c_kursor_pracownicy IS SELECT FIRST_NAME FROM employees; FOR r_pracownik IN c_kursor_pracownicy LOOP dbms_output.put_line(r_pracownik.first_name); END LOOP; 25
Parametry kursorów Kursory mogą mieć zdefiniowane parametry. Parametry w kursorach stosujemy, gdy chcemy uzależnić wyniki zwracane przez kursor od wartości, których nie znamy podczas pisania programu. 26
Parametry kursorów Kursor z parametrami należy deklarować w następujący sposób: CURSOR nazwa_kursora (nazwa_parametru typ_parametru) IS zapytanie_wykorzystujące_parametr; 27
Parametry kursorów Kursor z parametrami należy otwierać w następujący sposób: OPEN nazwa_kursora(wartość_parametru); Aby wykorzystać pętlę przetwarzającą kursor korzystamy z następującego zapisu: FOR zmienna IN LOOP; nazwa_kursora(wartość_parametru) 28
Parametry kursorów - przykład DECLARE CURSOR c_kursor_pracownicy (ps_do_litery VARCHAR2) IS SELECT FIRST_NAME FROM employees WHERE LAST_NAME < ps_do_litery; FOR r_pracownik IN c_kursor_pracownicy( E ) LOOP dbms_output.put_line(r_pracownik.first_name); END LOOP; 29
Kod składowany Zestaw instrukcji realizujący pewną funkcjonalność Przechowywany w bazie danych jako obiekt bazodanowy Może być wykorzystywany przez inne programy Umożliwia dekompozycję programu na mniejsze części Ułatwia projektowanie i naprawianie błędów Ułatwia ponowne użycie kodu w innych systemach 30
Typy kodu składowanego Typ Procedura składowana (stored procedure) Funkcja składowana (stored function) Opis Obiekt realizujący pewną funkcjonalność. Może przyjmować dowolną ilość parametrów wejściowych i zwracać dowolną ilość parametrów wyjściowych. Obiekt realizujący pewną funkcjonalność. Może przyjmować dowolną ilość parametrów wejściowych i zwracać dowolną ilość parametrów wyjściowych. Jako wynik zwraca pojedynczą wartość. 31
Typy kodu składowanego Typ Pakiet składowany (stpred package) Wyzwalacz (trigger) Opis Kontener na procedury, funkcje, zmienne i typy. Stosowany w celu zgrupowania powiązanych procedur i funkcji w jednym miejscu. Zdefiniowany na tabeli, wykonuje się podczas operacji INSERT, UPDATE oraz DELETE. 32
Kod składowany Kod składowany tworzy się za pomocą słów kluczowych CREATE OR REPLACE CREATE OR REPLACE PROCEDURE log (ps_tekst IN varchar2)is DBMS_OUTPUT.PUT_LINE (ps_tekst); 33
Procedura Może przyjmować dowolną ilość parametrów wejściowych i zwracać dowolną ilość parametrów wyjściowych. 34
Procedura Budowa procedury CREATE OR REPLACE PROCEDURE nazwa_procedury (parametr1 IN/OUT typ, parametr2 IN/OUT typ, ) IS deklaracja zmiennych instrukcje PL/SQL EXCEPTION obsługa wyjątków 35
Procedura Przykład procedury PROCEDURE log (ps_tekst IN varchar2) IS DBMS_OUTPUT.PUT_LINE (ps_tekst); Nazwa procedury Wejściowy parametr tekstowy 36
Lista parametrów Lista parametrów definiuje nazwy parametrów, tryb dostępu oraz typ parametru Parametry są oddzielone od siebie przecinkami i umieszczone w nawiasach 37
Lista parametrów Tryb dostępu określa w jaki sposób procedura może korzystać z wartości parametru IN parametr jest parametrem wejściowym, procedura może tylko czytać jego wartość OUT parametr jest parametrem wyjściowym, procedura może tylko ustawiać jego wartość IN OUT parametr jest parametrem możliwym do odczytu i do zapisu przez procedurę 38
Przykład listy parametrów CREATE OR REPLACE PROCEDURE test_parametrow ( pn_parametr1 IN NUMBER, ps_parametr2 OUT VARCHAR2, pd_parametr3 IN OUT DATE, pn_parametr4 OUT NUMBER, pn_parametr5 IN VARCHAR2 ) 39
Lista parametrów Przykład demonstrujący parametr wyjściowy CREATE OR REPLACE PROCEDURE format_sysdate(ps_f OUT VARCHAR2) IS ps_f := TO_CHAR(SYSDATE, YYYY-MONTH-DD ); -- DECLARE ls_formatted_date VARCHAR2(50); format_sysdate (ps_f => ls_formatted_date); dbms_output.put_line( Dzis jest ls_formatted_date); 40
Lista parametrów Przykład demonstrujący parametr wejściowy-wyjściowy CREATE OR REPLACE PROCEDURE add_10(pn_liczba IN OUT NUMBER) IS pn_liczba := pn_liczba+10; -- DECLARE ln_liczba NUMBER := 1; add_10(ln_liczba); dbms_output.put_line( 1+10= ln_liczba); 41
Koniec pracy procedury Procedura kończy swoją pracę gdy: Sterowanie dojdzie do końca procedury Zostanie napotkany rozkaz RETURN; Podniesiony zostanie nieobsłużony wyjątek 42
Koniec pracy procedury - przykład CREATE OR REPLACE PROCEDURE test1 (ps_p1 IN VARCHAR2) IS DBMS_OUTPUT.PUT_LINE( Start ); IF ps_p1 = NOC THEN RETURN; END IF; DBMS_OUTPUT.PUT_LINE( Nie ma nocy ); Uruchomienie Test1( DZIEŃ ); Wynik Start Nie ma nocy Test1( NOC ); Start 43
Przykład procedury składowanej CREATE OR REPLACE PROCEDURE wyswietl_date(pd_date IN DATE) IS DBMS_OUTPUT.PUT_LINE( TO_CHAR(pd_date, DD-MM-YYYY ) ); 44
Uruchamianie procedury składowanej Z klienta sqlplus: EXECUTE wyswietl_date(sysdate); Z anonimowego bloku PL/SQL: wyswietl_date(sysdate); 45
Uruchamianie procedury składowanej Z innej procedury: PROCEDURE test IS dbms_output.put_line( Start ); wyswietl_date(sysdate); 46
Uruchamianie procedury składowanej Z procedury napisanej w języku Java: String = wyswietldatecall "\n" + " wyswietl_date(:1);\n" + ""; DBTransaction txn = getdbtransaction(); CallableStatement cs = txn.createcallablestatement(wyswietldatecall, 1); try { cs.setdate(1, datasystemowa); cs.execute(); } catch (SQLException e) { throw new Exception(e.getLocalizedMessage()); } 47
Procedura nie musi być składowana Przykład demonstrujący stosowanie funkcji w anonimowym bloku PL/SQL DECLARE -- PROCEDURE log (ps_tekst IN varchar2)is DBMS_OUTPUT.PUT_LINE(ps_tekst); -- Log( To ); Log( jest ); Log( Test ); 48
Funkcja Może przyjmować dowolną ilość parametrów wejściowych i zwracać dowolną ilość parametrów wyjściowych. Zawsze musi zwrócić wartość o typie zdefiniowanym w deklaracji funkcji. W tym celu należy wykorzystać konstrukcję: RETURN wartość; np. RETURN 10; 49
Funkcja Budowa funkcji FUNCTION nazwa_funkcji (parametr1 IN/OUT typ, parametr2 IN/OUT typ, ) RETURN typ_wartości_wyjściowej IS deklaracja zmiennych instrukcje PL/SQL EXCEPTION obsługa wyjątków 50
Funkcja Przykład demonstrujący funkcję CREATE OR REPLACE FUNCTION add_10(pn_liczba IN NUMBER) RETURN NUMBER IS RETURN pn_liczba+10; 51
Uruchamianie funkcji składowanej Z anonimowego bloku PL/SQL: DECLARE ln_liczba NUMBER; ln_liczba := add_10(1); 52
Uruchamianie funkcji składowanej Z innej funkcji lub procedury CREATE OR REPLACE PROCEDURE test IS ln_liczba NUMBER; ln_liczba := add_10(1); 53
Uruchamianie funkcji składowanej Jako parametr innej funkcji lub procedury dbms_output.put_line(add_10(1)); dbms_output.put_line(add_10(add_10(1))); 54
Uruchamianie funkcji składowanej Funkcje składowane można stosować w zapytaniach SELECT na przykład: SELECT add_10(salary) FROM employees; Funkcje wykorzystywane w zapytaniach SELECT muszą spełniać następujące kryteria: Nie mogą mieć parametrów wyjściowych, ani parametrów wejścia-wyjścia Nie mogą wykonywać instrukcji INSERT/UPDATE/DELETE Nie mogą wykonywać instrukcji COMMIT i ROLLBACK 55
Koniec pracy funkcji Funkcja kończy swoją pracę gdy: Zostanie napotkany rozkaz RETURN <wartość>; Podniesiony zostanie nieobsłużony wyjątek Gdy sterowanie dojdzie do końca funkcji, podniesiony zostanie wyjątek Powrót z funkcji bez wartości. Jest to sytuacja nieprawidłowa. 56
Funkcja przykład Przykład demonstrujący funkcję CREATE OR REPLACE FUNCTION slownie(pn_liczba IN NUMBER) RETURN VARCHAR2 IS IF pn_liczba = 1 THEN RETURN Jeden ; END IF; IF pn_liczba = 2 THEN RETURN Dwa ; END IF; IF pn_liczba = 3 THEN RETURN Trzy ; END IF; RETURN Nieobsługiwana liczba! ; 57
Funkcja nie musi być składowana Przykład demonstrujący stosowanie funkcji w anonimowym bloku PL/SQL DECLARE -- FUNCTION add_10(pn_liczba IN NUMBER) RETURN NUMBER IS RETURN pn_liczba+10; -- dbms_output.put_line( 1+10= add_10(1)); 58
Procedury zagnieżdżone Procedury mogą mieć swoje procedury i funkcje PROCEDURE procedura1 () IS FUNCTION funkcja1 ( ) RETURN NUMBER IS DECLARE PROCEDURE procedura2 ( ) IS FUNCTION funkcja2 ( ) RETURN VARCHAR2 IS 59