Plan wykładu BAZY DANYCH II WYKŁAD 9 Dynamiczny SQL, NDS, EXECUTE IMMEDIATE, Pakiet DBMS_SQL, Obiekty w PL/SQL, Tworzenie, wywoływanie, dziedziczenie, etc. dr inż. Agnieszka Bołtuć Dynamiczny SQL Pozwala na uruchamianie instrukcji SQL bez znajomości kolumn i tabel występujących w tych instrukcjach, Statyczny SQL ma swoje zalety takie jak wiedza o dostępności potrzebnych obiektów, poprawnym zdefiniowaniu uprawnień już w czasie kompilowania lub testowania, ponadto statyczny kod SQL można modyfikować pod względem optymalnej wydajności, Dynamiczny SQL Jednak znajomość i używanie dynamicznego SQL jest praktycznie niezbędna, Dzięki niemu można dołączać instrukcje DDL do programów PL/SQL, dysponować kodem który dostosowuje się do zmian w tabelach, a także umożliwia obsługę różnych danych wejściowych użytkownika w programach składowanych, Dynamiczny SQL można używać wybierając język NDS lub pakiet DBMS_SQL, 1
Kiedy używać dynamicznego SQL NDS Wtedy gdy pełna składnia zapytania SQL jest nieznana w czasie wykonywania, Gdy nieznane są polecenia, klauzule zapytania SQL, Gdy nieznane są tabele, kolumny, indeksy, sekwencje, nazwy użytkowników, etc., Gdy chcesz aby kod był bardziej ogólny i elastyczny, NDS (z ang. Native Dynamic SQL) wbudowany dynamiczny język SQL, Narzędzie do uruchamiania dynamicznego kodu SQL, jest szybsze i bardziej efektywne niż pakiet DBMS_SQL, Umożliwia bezpośrednie korzystanie z kolekcji i typów obiektowych, Ma składnię odzwierciedlającą składnię instrukcji statycznych, NDS EXECUTE IMMEDIATE Może pobierać dane do rekordów, czego nie robi pakiet, Obsługuje wszystkie typy danych języka PL/SQL, które można było użyć w statycznych instrukcjach SQL, Bazuje na instrukcji EXECUTE IMMEDIATE, Służy do przetwarzania i wykonywania dynamicznego SQL, przyjmuje ona jeden argument będący łańcuchem znaków (VARCHAR2), Łańcuch znaków to polecenie w języku SQL bez uwzględnienia w nim średnika, Średnik uwzględniamy wówczas gdy łańcuchem znaków jest blok anonimowy, 2
EXECUTE IMMEDIATE EXECUTE IMMEDIATE EXECUTE IMMEDIATE łańcuch_znaków [INTO {zmienna [,zmienna] rekord}] [USING [IN OUT IN OUT] zmienna_wiązana [, [IN OUT IN OUT] zmienna_wiązana] ]; łańcuch_znaków to dynamiczne zapytanie SQL bez średnika lub blok anonimowy ze średnikiem, zmienne, rekord zmienne PL/SQL przechowujące wartości kolumn, rekord przechowuje wybrany wiersz, zmienna_wiązana wartość wyrażenia przekazywana do dynamicznego SQL lub bloku anonimowego, EXECUTE IMMEDIATE INTO używane dla jednowierszowych zapytań, specyfikuje zmienne lub rekord do których zapisane będą wartości ze zwracanych przez zapytanie kolumn, USING używany do ładowania zmiennych wiązanych, tryb domyślny IN, jako zmienne wiązane nie można używać wartości typu BOOLEAN, Metody wykonywania dynamicznego SQL Polecenia DML i DDL bez zmiennych powiązanych Polecenia DML ze znaną listą zmiennych powiązanych, Polecenia DQL. 3
Metoda nr 1 Metoda nr 1 CREATE OR REPLACE PROCEDURE tworz (nazwa_tab VARCHAR2, kolumny VARCHAR2) IS EXECUTE IMMEDIATE CREATE TABLE nazwa_tab ( kolumny ) ; / tworz( employees_new, id NUMBER PRIMARY KEY, nazwa VARCHAR2(20), pensja NUMBER ); CREATE OR REPLACE PROCEDURE tworz (nazwa_tab VARCHAR2, kolumny VARCHAR2) IS v_lan VARCHAR2(100) := CREATE TABLE nazwa_tab ( kolumny ) ; EXECUTE IMMEDIATE v_lan; / tworz( employees_new, id NUMBER PRIMARY KEY, nazwa VARCHAR2(20), pensja NUMBER ); Metoda nr 2 CREATE OR REPLACE PROCEDURE dodaj (nazwa_tab VARCHAR2, p_id NUMBER, p_nazwa VARCHAR2) IS EXECUTE IMMEDIATE INSERT INTO nazwa_tab VALUES (:1,:2) USING p_id, p_nazwa ; Jednowierszowe instrukcje - przykład CREATE FUNCTION pobierz (p_id NUMBER) RETURN departments%rowtype IS v_lan VARCHAR2(200); v_dep departments%rowtype; v_lan:= SELECT * FROM departments WHERE department_id=:p_id ; EXECUTE IMMEDIATE v_lan INTO v_dep USING p_id; RETURN v_dep; 4
Bloki anonimowe - przykład Metoda nr 3 CREATE FUNCTION zwrot RETURN NUMBER IS v_lan VARCHAR2(200):= DECLARE r_emp employees%rowtype; SELECT * INTO r_emp FROM employees WHERE employee_id=100; :zwr :=r_emp.salary*1.2; ; v_zwr NUMBER; EXECUTE IMMEDIATE v_lan USING OUT v_zwr; RETURN v_zwr; NDS działa tylko dla typów bazy danych, korzystając z kolekcji trzeba ja najpierw definiować w bazie, Operacje masowe na kolekcjach mogą być w NDS wykonywane tylko jako zawarte w blokach PL/SQL, DBMS_SQL nie obsługuje typów zdefiniowanych przez użytkownika, Pakiet DBMS_SQL Przykładowe funkcje pakietu Wprowadzony w Oracle 7, Służy do wykonywania dynamicznych zapytań SQL, Bardziej złożony niż NDS, jednak niezbędny w szczególnych przypadkach np. gdy lista SELECT jest nieznana, describe dbms_sql; - lista procedur dostępnych z pakietu DBMS_SQL, OPEN_CURSOR otwiera nowy kursor i zwraca jego ID, DBMS_SQL.OPEN_CURSOR RETURN INTEGER; CLOSE_CURSOR zamyka kursor, EXECUTE wykonuje kursor (podany przez ID) i zwraca liczbę przetworzonych wierszy, DBMS_SQL.EXECUTE ( c IN INTEGER) RETURN INTEGER; 5
Przykładowe funkcje pakietu Przykładowe funkcje pakietu PARSE dokonanie analizy i weryfikacji zapytania SQL, powiązanie z kursorem, przetwarzane jest dowolne zapytanie DML lub DDL, DBMS_SQL.PARSE ( c IN INTEGER, statement IN VARCHAR2, language_flag IN INTEGER); BIND_VARIABLE wiąże podane wartości ze zmiennymi w kursorze, DBMS_SQL.BIND_VARIABLE ( c IN INTEGER, name IN VARCHAR2, value IN <datatype>); FETCH_ROWS pobiera wiersze z kursora o danym ID, DBMS_SQL.FETCH_ROWS ( c IN INTEGER) RETURN INTEGER; Przykładowe funkcje pakietu IS_OPEN sprawdza czy podany kursor jest otwarty, DBMS_SQL.IS_OPEN ( c IN INTEGER) RETURN BOOLEAN; DEFINE_COLUMN definiuje kolumnę która ma być pobrana z kursora, DBMS_SQL.DEFINE_COLUMN ( c IN INTEGER, position IN INTEGER, column IN <datatype>); Przykład 1 usuwanie rekordów CREATE OR REPLACE FUNCTION usuwanie (p_tabela VARCHAR2) RETURN NUMBER IS v_id_kursor INTEGER; v_ile_usun NUMBER; v_id_kursor:=dbms_sql.open_cursor; DBMS_SQL.PARSE(v_id_kursor, DELETE FROM p_tabela, DBMS_SQL.NATIVE); v_ile_usun:=dbms_sql.execute(v_id_kursor); DBMS_SQL.CLOSE_CURSOR(v_id_kursor); RETURN v_ile_usun; 6
Przykład 2 Porównanie NDS i DBMS_SQL CREATE OR REPLACE PROCEDURE dodawanie (p_tabela VARCHAR2, p_id NUMBER, p_nazwa VARCHAR2) IS v_id_kursor INTEGER; v_ile_dod NUMBER; v_id_kursor:=dbms_sql.open_cursor; DBMS_SQL.PARSE(v_id_kursor, INSERT INTO p_tabela VALUES (:c_id, :c_name), DBMS_SQL.NATIVE); DBMS_SQL.BIND_VARIABLE(v_id_kursor, :c_id,p_id); DBMS_SQL.BIND_VARIABLE(v_id_kursor, :c_nazwa,p_nazwa); v_ile_dod:=dbms_sql.execute(v_id_kursor); DBMS_SQL.CLOSE_CURSOR(v_id_kursor); DBMS_OUTPUT.PUT_LINE(v_ile_dod); CREATE PROCEDURE insert_into_table ( table_name VARCHAR2, deptnumber NUMBER, deptname VARCHAR2, location VARCHAR2) IS stmt_str VARCHAR2(200); stmt_str := 'INSERT INTO ' table_name ' values (:deptno, :dname, :loc)'; EXECUTE IMMEDIATE stmt_str USING deptnumber, deptname, location; źródło: dokumentacja Oracle NDS Porównanie NDS i DBMS_SQL Typ obiektowy CREATE PROCEDURE insert_into_table ( table_name VARCHAR2, deptnumber NUMBER, deptname VARCHAR2, location VARCHAR2) IS cur_hdl INTEGER; stmt_str VARCHAR2(200); rows_processed BINARY_INTEGER; stmt_str := 'INSERT INTO ' table_name ' VALUES (:deptno, :dname, :loc)'; cur_hdl := dbms_sql.open_cursor; dbms_sql.parse(cur_hdl, stmt_str, dbms_sql.native); dbms_sql.bind_variable (cur_hdl, ':deptno', deptnumber); dbms_sql.bind_variable (cur_hdl, ':dname', deptname); dbms_sql.bind_variable (cur_hdl, ':loc', location); rows_processed := dbms_sql.execute(cur_hdl); dbms_sql.close_cursor(cur_hdl); DBMS_SQL źródło: dokumentacja Oracle Obsługa programowania obiektowego w PL/SQL została wprowadzona w wersji Oracle 8, Typy obiektowe w PL/SQL przypominają pakiet, mają specyfikację i ciało, 7
Specyfikacja Specyfikacja - przykład Zawiera atrybuty i deklaracje metod, Specyfikacja jest publiczna, CREATE [OR REPLACE] TYPE [schemat.]nazwa [AUTHID {CURRENT_USER DEFINER}] AS OBJECT (atrybut1 typ_danych, [metoda1]); CREATE OR REPLACE TYPE ksiegarnia AS OBJECT ( Id NUMBER, num_dod NUMBER, Cena NUMBER(10,2), Rok_wydania DATE, ); Atrybuty Atrybuty Musza znaleźć się przed metodami, Typem może być dowolny typ danych bazy, PL/SQL lub zdefiniowany w pakiecie; nie można używać tych, które dostępne są w PL/SQL ale nie obsługuje ich baza (np. PLS_INTEGER), Nie można nadawać ogranicznika NOT NULL, Należy zadeklarować przynajmniej jeden atrybut, Brak możliwości nadawania deklaracji domyślnych, Nie można używać %TYPE ani %ROWTYPE do atrybutów typów obiektowych, można do atrybutów obiektów, Atrybut może być typu innego obiektu, to pozwala na tworzenie złożonych typów obiektowych, 8
Metody Metody składowe Funkcje lub procedury zdeklarowane w specyfikacji, [STATIC MEMBER] PROCEDURE specyfikacja; [STATIC MEMBER CONSTRUCTOR] FUNCTION specyfikacja; [MAP ORDER] MEMBER FUNCTION specyfikacja; Można je wywoływać przy użyciu notacji bazującej na pozycjach lub nazwach, Parametry mogą mieć nazwy domyślne (DEFAULT), Można je przeciążać przy użyciu typu i liczby argumentów, Są wywoływane dla samych obiektów a nie typów obiektowych, Metody składowe Metody statyczne CREATE OR REPLACE TYPE obnizka AS OBJECT ( rabat NUMBER(10,4), cena NUMBER(10,2), MEMBER FUNCTION obn RETURN NUMBER); DECLARE v_o OBNIZKA :=obnizka(.1,65.00); v_war NUMBER(10); v_war:=v_o.obn; DBMS_OUTPUT.PUT_LINE(v_war); Są niezależne od egzemplarza obiektu, Do wywołania trzeba użyć typu obiektowego, a nie egemplarza, Szczególnie użyteczne w wersjach przed Oracle 9iR2 do definiowania konstruktorów definiowanych przez użytkownika, 9
Metody statyczne Konstruktory CREATE OR REPLACE TYPE obnizka AS OBJECT ( rabat NUMBER(10,4), cena NUMBER(10,2), STATIC FUNCTION nowa_cena ( p_cena IN NUMBER, p_rabat IN NUMBER DEFAULT.1) RETURN NUMBER); exec DBMS_OUTPUT.PUT_LINE(obnizka.nowa_cena(85)); Od wersji Oracle 9iR2, Służą do przesłonięcia konstruktorów predefiniowanych przez system lub tworzenia dodatkowych konstruktorów, Gdy typ obiektowy i konstruktor mają tę samą nazwę i liczbę atrybutów to nowy konstruktor zastępuje ten zdefiniowany przez system, Konstruktory CREATE OR REPLACE TYPE obnizka AS OBJECT ( rabat NUMBER(10,4), cena NUMBER(10,2), CONSTRUCTOR FUNCTION obnizka ( cena NUMBER) RETURN SELF AS RESULT); Deklarowanie i inicjowanie DECLARE v_p obnizka; v_p.cena:=85; DBMS_OUTPUT.PUT_LINE(v_p.cena); DECLARE v_p obnizka :=obnizka(null,null); v_p.cena:=85; DBMS_OUTPUT.PUT_LINE(v_p.cena); 10
Ciało typów obiektowych Ciało typów obiektowych Zawiera ciała metod typu obiektowego, CREATE [OR REPLACE] TYPE BODY [schemat.]nazwa {IS AS} [STATIC MEMBER] PROCEDURE ciało; [STATIC MEMBER CONSTRUCTOR] FUNCTION ciało; [MAP ORDER] MEMBER FUNCTION ciało; CREATE OR REPLACE TYPE BODY obnizka AS MEMBER FUNCTION obn RETURN NUMBER IS RETURN (cena*(1-rabat)); SELF MAP i ORDER Wskazuje bieżący egzemplarz obiektu, Jest on automatycznie deklarowany jako pierwszy parametr metod składowych (IN funkcje składowe, IN OUT procedury składowe), Używa się go obowiązkowo w konstruktorach definiowanych przez użytkownika, Konieczne również przy przekazywaniu bieżącego obiektu lub referencji do niego jako argumentu do innej procedury lub funkcji, Nie stosuje się w metodach statycznych, Pozwalają na porównanie dwóch obiektów, Mogą służyć do sortowania obiektów w bazie danych, W obiekcie może być tylko jedna metoda MAP lub ORDER, Nie może być obu metod jednocześnie, W przypadku braku ich definicji program zgłosi wyjątek, 11
MAP MAP - przykład Przekształca obiekt na typ umożliwiający sortowanie, Bardziej wydajna niż ORDER, Przyjmuje wyłącznie parametry SELF, a zwraca typ skalarny: DATE, NUMBER, VARCHAR2, CHAR, REAL, Porównaniu obj_1 > obj_2 odpowiada porównanie obj_1.map() > obj_2.map(), CREATE OR REPLACE TYPE rectangle_typ AS OBJECT ( len NUMBER, wid NUMBER, MAP MEMBER FUNCTION area RETURN NUMBER); CREATE OR REPLACE TYPE BODY rectangle_typ AS MAP MEMBER FUNCTION area RETURN NUMBER IS RETURN len * wid; END area; źródło: dokumentacja Oracle ORDER Przyjmuje jeden parametr typu obiektowego, Zwraca wartość typu NUMBER, Odpowiada na pytanie czy dany obiekt jest mniejszy, większy czy równy podanemu, Tak jak MAP jest wołana automatycznie gdy zaistnieje potrzeba porównania obiektów, ORDER - przykład CREATE OR REPLACE TYPE location_typ AS OBJECT (building_no NUMBER, city VARCHAR2(40), ORDER MEMBER FUNCTION match (l location_typ) RETURN INTEGER ); CREATE OR REPLACE TYPE BODY location_typ AS ORDER MEMBER FUNCTION match (l location_typ) RETURN INTEGER IS IF building_no < l.building_no THEN RETURN -1; ELSIF building_no > l.building_no THEN RETURN 1; ELSE RETURN 0; END IF; źródło: dokumentacja Oracle 12
ORDER - przykład Dziedziczenie DECLARE loc location_typ; secloc location_typ; a number; loc location_typ:=location_typ(300, 'San Francisco'); secloc location_typ :=location_typ(200, 'Redwood Shores'); a := loc.match(secloc); DBMS_OUTPUT.PUT_LINE('order (1 is greater, -1 is lesser):' a); Pozwala na przejmowanie przez typ obiektowy atrybutów i metod obiektowego typu nadrzędnego, CREATE OR REPLACE TYPE obnizka AS OBJECT ( rabat NUMBER(10,4), cena NUMBER(10,2), MEMBER FUNCTION obn RETURN NUMBER) ) INSTANTIABLE FINAL; źródło: dokumentacja Oracle Dziedziczenie Dziedziczenie INSTANTIABLE słowo oznacza że można tworzyć obiekty danego typu, NOT INSTANTIABLE gdy chcemy aby służył wyłącznie jako typ nadrzędny, wówczas można dziedziczyć jego atrybuty i metody, domyślnie INSTANTIABLE, FINAL oznacz że typ nie będzie miał typów pochodnych, gdy NOT FINAL można tworzyć typy pochodne, domyślnie FINAL, Typ bazowy tworzymy ze słowami kluczowymi: INSTANTIABLE NOT FINAL; Typ pochodny CREATE OR REPLACE TYPE nowy UNDER typ_bazowy ( ) INSTANTIABLE FINAL; 13
Dziedziczenie Modyfikowanie i usuwanie typów Zastępowanie metod typu bazowego w typie pochodnym OVERRIDING MEMBER PROCEDURE obn Typ bazowy i typy pochodne są w relacji jeden do wielu, typ bazowy może być powiązany z wieloma pochodnymi, zaś pochodny może mieć jeden typ bazowy, ALTER TYPE nazwa COMPILE [SPECIFICATION BODY]; Gdy brak SPECIFICATION lub BODY obie części są kompilowane razem, Wprowadzenie atrybutu: ALTER TYPE nazwa; ADD ATTRIBUTE nazwa_arg typ_danych; Usunięcie atrybutu: ALTER TYPE nazwa; DROP ATTRIBUTE nazwa_arg CASCADE; Modyfikowanie i usuwanie typów Modyfikowanie i usuwanie typów Dodanie metody do specyfikacji: ALTER TYPE nazwa ADD CONSTRUCTOR FUNCTION nazwa (parametry) RETURN SELF AS RESULT CASCADE; Usunięcie metody: ALTER TYPE nazwa DROP CONSTRUCTOR FUNCTION nazwa (parametry) RETURN SELF AS RESULT CASCADE; Usuwanie typów obiektowych: DROP TYPE nazwa; DROP TYPE nazwa FORCE; 14
WYKORZYSTANA LITERATURA J. Price, Oracle Database 11g i SQL. Programowanie. Helion, 2009. S. Urman, R. Hardman, M. McLaughlin, Oracle Database 10g. Programowanie w języku PL/SQL. Helion, 2008. www.oracle.com 15