2010-11-10 Plan wykładu BAZY DANYCH II WYKŁAD 3 Zasięg zmiennych Zmienne powiązane Instrukcje warunkowe Pętle Pobieranie danych – SQL w PL/SQL Rekordy dr inż. Agnieszka Bołtuć Zasięg zmiennych Zmienna jest dostępna tylko w bloku, w którym jest zadeklarowana, Kiedy zmienna wychodzi z zasięgu, system zwalnia i pamięć i takiej zmiennej nie można używać, Zmienna z bloku zagnieżdżonego jest niewidoczna w bloku zewnętrznym, Zmienna zadeklarowana w bloku zewnętrznym jest widoczna w bloku zagnieżdżonym. Zasięg zmiennych v_nazwa dostępna jest DECLARE w całym bloku v_nazwa VARCHAR2(20); BEGIN DECLARE v_druga_nazwa VARCHAR2(20); BEGIN v_druga_nazwa dostępna jest … w bloku zagnieżdżonym END; END; 1 2010-11-10 Widoczność zmiennych Gdy mam dwie zmienne o tych samych nazwach zadeklarowane w bloku zewnętrznym i zagnieżdżonym to zmienna ta jest ukryta w bloku wewnętrznym, Można to rozwiązać używając etykiet. Etykiety <<l_zewnetrzna>> DECLARE v_nazwa VARCHAR2(20); BEGIN DECLARE v_nazwa NUMBER(2); BEGIN l_zewnetrzna.v_nazwa:=’blok_zew’; DBMS_OUTPUT.PUT_LINE(l_zewnetrzna.v_nazwa); END; END; Widoczność zmiennych DECLARE v_nazwa VARCHAR2(20); BEGIN DECLARE v_nazwa VARCHAR2(20); BEGIN … END; END; Zmienne powiązane tzw. zmienne środowiskowe, podobne własności do zmiennych globalnych, Widoczne i dostępne w wielu programach, Często używane są do przekazywania wartości z PL/SQL do SQL, do optymalizacji zapytań, W PL/SQL zachowują się jak zwykłe zmienne. 2 2010-11-10 Zmienne powiązane Zmienne powiązane - przykład deklaracja VARIABLE nazwa typ_danych; VARIABLE v_imie VARCHAR2(20); BEGIN SELECT first_name INTO :v_imie FROM employees WHERE employee_id=200; END; / PRINT v_imie; Zmienne powiązane - przykład Zmienne powiązane - przykład VARIABLE v_imie VARCHAR2(20); BEGIN :v_imie :=’LEX’; END; / PRINT v_imie; SELECT last_name FROM employees WHERE first_name= :v_imie; VARIABLE v_imie VARCHAR2(20); SET AUTOPRINT ON; BEGIN automatyczne włączenie wyświetlania zmiennych powiązanych :v_imie :=’LEX’; END; / SELECT last_name FROM employees WHERE first_name= :v_imie; odwołanie do zmiennej :nazwa wyświetlenie zawartości zmiennej PRINT nazwa; 3 2010-11-10 Struktury sterujące Wykonywanie warunkowe Wykonywanie w pętli Nawigacja sekwencyjna IF-THEN-ELSE IF warunek THEN operacje; [ELSE operacje;] END IF; IF-THEN IF warunek THEN operacje; END IF; DECLARE v_wiek NUMBER := 19; BEGIN IF v_wiek>=18 THEN DBMS_OUTPUT.PUT_LINE(’Jesteś pełnoletni’); END IF; END; IF-THEN-ELSE DECLARE v_wiek NUMBER := 19; BEGIN IF v_wiek>=18 THEN DBMS_OUTPUT.PUT_LINE(’Jesteś pełnoletni’); ELSE DBMS_OUTPUT.PUT_LINE(’Nie jesteś pełnoletni’); END IF; END; 4 2010-11-10 IF-THEN-ELSEIF IF warunek THEN operacje; [ELSIF warunek THEN operacje;] [ELSE operacje;] END IF; IF-THEN-ELSEIF DECLARE v_wiek NUMBER := 19; BEGIN IF v_wiek<18 THEN DBMS_OUTPUT.PUT_LINE(’Nie jesteś pełnoletni’); ELSIF v_wiek<40 THEN DBMS_OUTPUT.PUT_LINE(’Nie jesteś w średnim wieku’); ELSE DBMS_OUTPUT.PUT_LINE(’Jesteś stary’); END IF; END; NULL w instrukcji IF CASE DECLARE Jeśli wyrażenie IF zwraca NULL to sterowanie jest przekazywane do ELSE v_wiek NUMBER; BEGIN IF v_wiek>=18 THEN DBMS_OUTPUT.PUT_LINE(’Jesteś pełnoletni’); END IF; END; Od wersji 9i, Alternatywa warunkowego wykonywania kodu, upraszczająca składnię, CASE warunek WHEN test1 THEN operacje; WHEN test1 THEN operacje; … [ELSE operacje;] END CASE; 5 2010-11-10 CASE DECLARE v_ocena VARCHAR2(1); v_ocena_konw NUMBER(1); BEGIN SELECT ocena INTO v_ocena FROM uczen WHERE przedmiot=’algebra’ and id=’11234’; CASE v_ocena WHEN ’A’ THEN v_ocena_konw:=5; WHEN ’B’ THEN v_ocena_konw:=4; … ELSE v_ocena_konw:=0; END CASE; END; CASE z wyszukiwaniem W takiej konstrukcji nie trzeba przekazywać wyrażenia na początku instrukcji CASE, Każda klauzula WHEN przyjmuje wyrażenie, którego wartość trzeba sprawdzić, Można podawać albo to samo wyrażenie w każdej klauzuli WHEN, lub za każdym razem inne. CASE z wyszukiwaniem Wykonywanie w pętli CASE WHEN v_dochod<85000 THEN v_podatek:=dochod*0.18; WHEN v_dochod>=85000 THEN v_podatek:=85000*0.18+(v_dochod-85000)*0.32; ELSE DBMS_OUTPUT.PUT_LINE(’Brak dochodu’); END CASE; Pętle proste Pętle liczbowe FOR Pętle WHILE 6 2010-11-10 Pętle proste LOOP operacje; EXIT [WHEN warunek]; END LOOP; Pętla FOR FOR licznik IN [REVERSE] liczba_porzadkowa..liczba_koncowa LOOP operacje; END LOOP; Pętle proste DECLARE v_licznik PLS_INTEGER :=1; BEGIN LOOP DBMS_OUTPUT.PUT_LINE(’Wiersz numer’ || v_licznik); v_licznik:=v_licznik+1; EXIT WHEN v_licznik=10; END LOOP; END; Pętla FOR BEGIN FOR v_licznik IN 1..9 LOOP DBMS_OUTPUT.PUT_LINE(’Wiersz numer’ || v_licznik); END LOOP; END; 7 2010-11-10 Pętla WHILE Pętla WHILE DECLARE v_licznik PLS_INTEGER :=1; BEGIN WHILE v_licznik<10 LOOP DBMS_OUTPUT.PUT_LINE(’Wiersz numer’ || v_licznik); v_licznik:=v_licznik+1; END LOOP; END; WHILE warunek LOOP operacje; END LOOP; Pętle i etykiety Pętle i etykiety Umożliwiają korzystanie z pętli tak, jakby miały nazwę, Nazywają nienazwane elementy języka PL/SQL, <<nazwa_petli>> pętla, instrukcje END LOOP nazwa_petli; Wówczas możemy używać konstrukcji typu: EXIT nazwa_petli; EXIT nazwa_petli WHEN v_licznik=10; opcjonalne 8 2010-11-10 CONTINUE Dodatkowe sterownie pętlą, Przekazuje sterowanie do następnej iteracji, Od wersji 11g, Można używać w połączeniu z etykietami. BEGIN FOR i IN 1..10 LOOP DBMS_OUTPUT.PUT_LINE( i ); CONTINUE WHEN i> 5 ; DBMS_OUTPUT.PUT_LINE(’tylko mniejsze, rowne 5′); END LOOP; END; Polecenie SELECT SQL w PL/SQL Polecenie SELECT SELECT lista_wyboru [INTO lista_zmiennych] FROM lista_tabel [WHERE warunki] [ORDER BY lista_kolumn]; PL/SQL nie wspiera bezpośrednio poleceń DDL i DCL, w tym celu należy używać dynamicznego SQL, PL/SQL wspiera także polecenia z zakresu obsługi transakcji, Do pobierania danych służy polecenie SELECT. Lista_wyboru – kolumny, łańcuchy, funkcje SQL, *, operacje arytmetyczne, Lista_zmiennych – zmienna lub grupa zmiennych odpowiadających wartościom z listy wyboru, typy skalarne, zakotwiczone lub rekordy, Lista_tabel – tabele, widoki, Pobrane wartości muszą trafić do zmiennej za pomocą INTO, Polecenie musi zwracać pojedynczy wiersz. 9 2010-11-10 Polecenie SELECT Polecenie SELECT DECLARE v_salary employees.salary%TYPE; v_last_name employees.last_name%TYPE; BEGIN SELECT last_name, salary INTO v_last_name, v_salary FROM employees WHERE employees_id=105; DBMS_OUTPUT.PUT_LINE(’Pracownik’||v_last_name); DBMS_OUTPUT.PUT_LINE(’Zarabia’||v_salary); END; DECLARE v_salary employees.salary%TYPE; v_jobs employees.job_id%TYPE :=’IT_PROG’; BEGIN SELECT AVG(salary) INTO v_salary FROM employees WHERE job_id=v_jobs; DBMS_OUTPUT.PUT_LINE(’Na stanowisku’||v_jobs); DBMS_OUTPUT.PUT_LINE(’Średnia płaca wynosi’||v_salary); END; Rekordy Rekordy Zbiór zmiennych różnych typów, Wprowadzone w bazie danych Oracle 7, Typami pól rekordu mogą być wszystkie typy danych dostępne w Oracle , zdefiniowane przez użytkownika oraz kolekcje, Bardzo często zawartość rekordów jest wzorowana na strukturze tabel z bazy danych, Może mieć dowolną liczbę pól, Pola mogą mieć zainicjowaną wartość oraz być zdefiniowane jako NOT NULL, Są definiowane w części deklaracyjnej bloków, funkcji czy procedur, Mogą być zagnieżdżone, Definiowane za pomocą atrybutu %ROWTYPE lub jawnie. 10 2010-11-10 %ROWTYPE Powoduje dziedziczenie definicji wierszy po kursorach, tabelach, obiektach lub widokach, Nazwy i typy pól rekordu są tworzone na podstawie wskazanego wiersza, Definicja jawna DECLARE v_employee employees%ROWTYPE; v_jobs jobs%ROWTYPE; Definiowanie typu rekordowego TYPE nazwa_rec IS RECORD (deklaracja_pola [,deklaracja_pola]…); Definiowanie zmiennej typu rekordowego Identyfikator nazwa_rec; Deklaracja pola nazwa_pola {typ | tabela.kolumna%TYPE | tabela%ROWTYPE} [[NOT NULL] { := | DEFAULT } wyrażenie] Deklaracja jawna Inicjowanie wartości pól DECLARE TYPE r_emp IS RECORD (v_numer NUMBER(2), v_pensja NUMBER(8) :=1000, v_zatrudnienie employees.hire_date%TYPE, v_spis jobs%ROWTYPE); BEGIN v_my_rec.v_pensja:=v_my_rec.v_pensja+200; v_my_rec.v_zatrudnienie:=sysdate; v_my_rec.v_numer:=1; v_my_rec r_emp; BEGIN … END; DBMS_OUTPUT.PUT_LINE(v_my_rec.v_numer || v_my_rec.v_spis.last_name || TO_CHAR(v_my_rec.v_zatrudnienie || TO_CHAR(v_my_rec.v_pensja) ); END; DECLARE identyfikator tabela%ROWTYPE; SELECT * INTO v_my_rec.v_spis FROM employees WHERE employee_id=105; 11 2010-11-10 Zagnieżdżanie Do tworzenia złożonych typów rekordowych można używać tylko jawnej definicji, Nie ma ograniczeń w zagnieżdżaniu, jeśli chodzi o poziomy, Wstawianie rekordu do tabeli DECLARE v_rec employees%ROWTYPE; BEGIN SELECT * INTO v_rec FROM employees WHERE employee_id=105; INSERT INTO new_employees VALUES (v_rec.employee_id, v_rec.first_name, v_rec.last_name, …); END; Wstawianie rekordu do tabeli Modyfikacja za pomocą rekordów DECLARE v_rec employees%ROWTYPE; DECLARE v_rec employees%ROWTYPE; v_hire_date employees.hire_date%TYPE; BEGIN BEGIN SELECT * INTO v_rec FROM employees WHERE employee_id=105; SELECT * INTO v_rec FROM employees WHERE employee_id=105; v_rec.hire_date:=sysdate; INSERT INTO new_employees VALUES v_rec; UPDATE employees SET ROW = v_rec WHERE employee_id=105; END; END; 12 2010-11-10 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 13