Rodzaje triggerów Triggery DML na tabelach INSERT, UPDATE, DELETE Triggery na widokach INSTEAD OF Triggery DDL CREATE, ALTER, DROP Triggery na bazie danych SERVERERROR, LOGON, LOGOFF, STARTUP, SHUTDOWN Triggery INSERT, UPDATE, DELETE Mogą być wykonane przed BEFORE lub po AFTER danej operacji. Mogą być wykonane dla każdego zmienianego wiersza FOR EACH ROW lub jednokrotnie dla pełnej realizacji instrukcji Przykład: Wykonujemy instrukcję: UPDATE USERS SET salary = salary * 2 WHERE name > 'P' Instrukcja podwaja zarobki osób, których imiona zaczynają się P i dalsze litery alfabetu zakładamy, że takich osbób jest kilkanaście. Przypadek 1: Dla tabeli USERS jest założony trigger: BEFORE UPDATE ON USERS FOR EACH ROW dosomething Procedura dosomething będzie wykonywana przed zmianą każdego wiersza, czyli zostanie wykonana tyle razy ile jest wierszy, które mają zostać zmienione. Przypadek 2: Dla tabeli USERS jest założony trigger: BEFORE UPDATE ON USERS dosomething Procedure dosomething będzie wykonana jednokrotnie przed wykonaniem polecenia, które wydaliśmy, czyli przed zaktualizowaniem pierwszego wiersza. Analogicznie z AFTER.
Triggery DML INSERT, UPDATE, DELETE Składania Tworzenie triggera CREATE [OR REPLACE] TRIGGER <nazwa triggera> <BEFORE lub AFTER> <instrukcja DML> [OR ] ON <nazwa tabeli> [FOR EACH ROW] [WHEN (<warunek z użyciem obiektów old i new>)] DECLARE BEGIN END; / Można wymienić jedną lub kilka instrukcji DML: INSERT INSERT OR UPDATE INSERT OR UPDATE OR DELETE itd.. W przypadku instrukcji UPDATE można wymienić kolumny tzn. Trigger zostanie wywołany tylko wtedy, gdy zmieni się wartość pola w podanej kolumnie, lub jednej z podanych kolumn. UPDATE OF <nazwa pola lub nazwy pól oddzielone przecinkami> Obiekty old i new Wewnątrz procedur triggerowych dostępnę są dwa szczególnie ważne obiekty: old i new, reprezentujące odpowiednio stary i nowy wiersz. Z przykładu old to wiersz, który zawiera jeszcze stare salary, a new to wiersz, który zawiera dwukrotnie większe salary; można wykorzystać to do obliczenia o ile wzrosła pensja: new.salary old.salary i zarejestrowania tego faktu w jakimś dzienniku BEFORE AFTER INSERT UPDATE DELETE Old bez znaczenia New wiersz, który będzie wstawiony do tabeli, można w nim zmienić wartości pól To samo, ale zmiana wartości pól w jakimkolwiek przypadku nie ma sensu; Old wiersz przed zmianą, zmiana wartości pól nie ma sensu New wiersz po zmianie, z zaktualizowanymi polami, można zmieniać w nim wartości pól To samo, ale zmiana wartości pól w jakimkolwiek przypadku nie ma sensu; Old wiersz, który zostanie za chwilę usunięty, zmiana wartości pól nie ma sensu New bez znaczenia To samo; Ponadto wiersz już nie istnieje Ponadto, wiersz new już istnieje Ponadto wiersz już został zaktualizowany
Jak dowiedzieć się dla jakiej instrukcji DML (INSERT, UPDATE, DELETE) został wywoały trigger? Służą do tego predykaty, które przyjmują wartość prawy lub fałszu: INSERTING DELETING UPDATING UPDATING('<nazwa kolumny>') Zalecenia ORACLE Nie używać triggerów do sprawdzania poprawności danych, którą można wykonać za pomocą wbudowanych funkcji Oracle (np. Integrity constraints lub check constraints) Nie tworzyć zbyt długich triggerów, lepiej zawrzeć część kodu w osobnych procedurach wywoływanych z triggera Należy tworzyć triggery, które będą poprawne niezależnie od tego, który użytkownik będzie z nich korzystał Nie wolno tworzyć triggerów rekursywnych. Prowadzą one to zapętlenia i wyczerpania zasobów pamięci. Zapytania do tej samej tabeli na której jest utworzony trigger, można wywoływać w triggerach AFTER Przykład triggera rekursywnego: AFTER UPDATE, taki, który wykonuje operacje UPDATE na tej samej tabeli, na której jest stworzony Przykłady zastosowania wykonanywanie skomplikowanej kontroli danych zapobieganie nieprawidłowym transakcjom zapewnianie integralności, której nie można zapewnić wbudowanymi funkcjami bazy danych implementacja złożonych reguł biznesowych implementacja złożonej autoryzacji transparentne rejestrowanie zdarzeń automatyczne generowanie wartości kolumn
Zadania Utworzyć tabelę USERS, która ma pola: ID, NAME, SALARY, CREATION_TIME, LAST_MODIFICATION_TIME Utworzyć tabelę USERS_LOG, która ma pola: ID, USER_ID, CHANGE_TIME, CHANGE_OF_SALARY Trigger może być użyty do automatycznego wstawiania daty i czasu wykonania zmiany danego wiersza (np. Mamy w jakiejś tabeli pole last_update_time) Można automatycznie wstawiać date i czas powstania rekordu (np. Mamy pole creation_time) Automatyczne logowanie zmian w jakiejś tabeli (np. Mamy tabelę osób, która zawiera aktualne wynagrodzenie i drugą tabelę, gdzie są zapisywane wszystkie zmiany wynagrodzenia dzięki triggerowi, dzieje się to automatycznie) Triggery na widokach INSTEAD OF Triggery na widokach są wykonywane zamiast danej operacji DML (INSERT, UPDATE, DELETE), a nie przed lub po niej, tak jak w przypadku triggerów DML. Działają one jedynie w trypie FOR EACH ROW. Składania CREATE [OR REPLACE] TRIGGER <nazwa triggera> INSTEAD OF <nazwa operacji DML> ON <nazwa tabeli> FOR EACH ROW DECLARE BEGIN END; / Przykład zastosowania Mamy dwie tabele: USERS z kolumnami ID, NAME, DEP_ID DEPARTMENTS z kolumnami ID, NAME Tabele połączone są po przez klucz obcy USERS.DEP_ID = DEPARTMENTS.ID Tworzymy widok CREATE VIEW UsersWithDepartmentView AS SELECT U.NAME AS 'USER_NAME', D.NAME AS 'DEP_NAME' FROM USERS U LEFT JOIN DEPARTMENTS D ON D.ID = U.DEP_ID który wyświetla nazwiska osób, a obok nich nazwę departamentu.
Zadania: Umożliwić operację INSERT na widoku UsersWithDepartmentView, która będzie dodawała użytkownika do tabeli USERS i wybierała odpowiedni DEP_ID lub będzie tworzyła nowy departament, jeśli jeszcze taki nie istnieje. Przykład: W tabeli USERS mamy: ID NAME DEP_ID 1 Thomas Brown 1 A w tabeli DEPARTMENTS mamy: ID NAME 1 Finances Instrukcja SELECT * FROM UsersWithDepartmentView zwróci nam: USER_NAME Thomas Brown DEP_NAME Finances Przypadek 1: INSERT INTO UsersWithDepartmentView (USER_NAME, DEP_NAME) VALUES ('Leszek Balcerowicz', 'Finances') powinna pobrać ID departamentu 'Finances' z tabeli DEPARTMENTS i wstawić odpowiedni rekord do tabeli USERS. Oczywiście, najpierw jeszcze ustalić unikalne ID dla nowego rekordu w tabeli USERS. Przypadek 2: INSERT INTO UsersWithDepartmentView (USER_NAME, DEP_NAME) VALUES ('Alfred Tarski', 'IT') powinna wstawić nowy departament do tabeli DEPARTMENTS, a następnie wstawić nowy rekord do tabeli USERS. Przypadek 3: INSERT INTO UsersWithDepartmentView (USER_NAME, DEP_NAME) VALUES ('Thomas Brown', 'IT') powinna pobrać ID departamentu 'IT' i w rekordzie 'Thomas Brown' powinna zmienić DEP_ID. Czyli: jeżeli departament nie istnieje to go założyć i nadać mu nowe ID jeżeli użytkownik nie istnieje to go utworzyć i nadać mu nowe ID i przydzielić do odpowiedniego departamentu
jeżeli użytkownik istnieje, to przydzielić go do odpowiedniego departamentu Inne operacje związane z triggerami Włączenie i wyłączanie triggerów ALTER TRIGGER <nazwa triggera> <ENABLE lub DISABLE> ALTER TABLE <nazwa tabeli> <ENABLE lub DISABLE> ALL TRIGGERS Rekompilacja triggera ALTER TRIGGER <nazwa triggera> COMPILE Usuwanie triggera DROP TRIGGER <nazwa triggera> Sprawdzanie błędów kompilacji SHOW ERRORS TRIGGER <nazwa triggera>;