Upload
others
View
5
Download
0
Embed Size (px)
Citation preview
Andreas Schmidt Trigger 1/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger
Andreas Schmidt Trigger 2/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger
• Konzept, um automatisch auf vordefini-erte Ereignisse in der Datenbank zu reag-ieren
• Trigger sind mit Datenbanktabelleverknüpft
• Auslösung durch DML Befehle INSERT,UPDATE und DELETE
• Einsatzbereiche:
• Datenintegrität
• Datensicherheit
• referentielle Integrität (besser durch Constraints)
• Produktivitätssteigerung
• Ausführungszeitpunkte:
• Vor der Ausführung des DML Befehls
• Nach der Ausführung des DML Befehls
• Anstelle eines DML-Befehls
• Bearbeitung durch Trigger bezieht sich entweder
• auf das DML-Statement (Statement Trigger)
• auf jeden einzelnen betroffenen Dat-ensatz (Row Trigger)
Andreas Schmidt Trigger 3/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger
• Syntax:CREATE [OR REPLACE] TRIGGER <Name>
{ BEFORE | AFTER | INSTEAD OF }
{ INSERT | DELETE | UPDATE } [OF <Spaltenliste> ]}
ON <Tabellenname>
[FOR EACH ROW]
[ WHEN (<Prädikat>)]
<Triggerrumpf>
• Erläuterungen
• INSTEAD OF Trigger bei Views1
• Vordefinierte Variablen :new und :old für den Zugriff auf die alten/neuen Werte (nur bei ROW-Trigger)
• WHEN darf keine SQL-Anfragen enthalten
• keine zyklischen Abhängigkeiten erlaubt
• Aktivieren/Deaktivieren eines Triggers:ALTER TRIGGER <TRIGGERNAME>
ENABLE | DISABLE;
• Tabelle user_triggers enthält Triggercode
1. funktioniert nicht bei Tabellen
Andreas Schmidt Trigger 4/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger Beispiele (ROW)
create or replace trigger example_row_trigger after update of population on my_city for each rowbegin dbms_output.put_line('Bevölkerungszuwachs in '||:old.name|| ' von '||:old.population||' auf '||:new.population);end;/
SQL> set serveroutput onSQL> update my_city set population=round(population*1.05) where country='D';
Bevölkerungszuwachs in Bremen von 549182 auf 576641Bevölkerungszuwachs in Stuttgart von 588482 auf 617906Bevölkerungszuwachs in Potsdam von 138268 auf 145181Bevölkerungszuwachs in Wiesbaden von 266081 auf 279385Bevölkerungszuwachs in Schwerin von 118291 auf 124206...
Andreas Schmidt Trigger 5/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger Beispiele (STATEMENT)
create or replace trigger example_statement_trigger after delete on my_citybegin dbms_output.put_line('User '||user()||
' hat ein DELETE Statement auf Tabelle my_city durchgeführt'); end;/show errors
SQL> delete my_citywhere population < 100000;
User SCAN0004 hat ein DELETE Statement auf Tabelle my_city durchgeführt
184 Zeilen wurden gelöscht.
SQL>
Andreas Schmidt Trigger 6/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger Beispiele (Check)
create or replace trigger check_establishment_timebefore insert on my_citybegin if to_char(sysdate,'HH24:MI') between '00:00' and '12:00' then raise_application_error(-20001,'Städte dürfen nur nachmittags gegründet werden'); end if;end;/show errors
SQL> insert into my_city (name, country, population)values('Smifftown', 'D', 142252352);
insert into my_city (name, country, population) *FEHLER in Zeile 1:ORA-20001: Städte dürfen nur nachmittags gegründet werdenORA-06512: in "SMIFF.CHECK_ESTABLISHMENT_TIME", Zeile 3ORA-04088: Fehler bei der Ausf³hrung von Trigger 'SMIFF.CHECK_ESTABLISHMENT_TIME'
Andreas Schmidt Trigger 7/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Abarbeitungsreihenfolge
create table trigger_test_table ( id number primary key, text varchar2(10));
create or replace TRIGGER before_updatebefore update on trigger_test_tablebegin dbms_output.put_line('before_update_stmt');end;/
create or replace TRIGGER after_updateafter update on trigger_test_tablebegin dbms_output.put_line('after_update_stmt');end;/
create or replace TRIGGER before_update_rowbefore update on trigger_test_tablefor each rowbegin dbms_output.put_line('before_update_row ('||
:old.text||'->'||:new.text||')');end;/
create or replace TRIGGER after_update_rowafter update on trigger_test_tablefor each rowbegin dbms_output.put_line('after_update_row ('||
:old.text||'->'||:new.text||')');end;/
Andreas Schmidt Trigger 8/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Abarbeitungsreihenfolge
insert into trigger_test_tablevalues(1, 'eins');
insert into trigger_test_tablevalues(2, 'zwei');
insert into trigger_test_tablevalues(3, 'drei');
set serveroutput on update trigger_test_table set text=upper(text) where id < 3;
before_update_stmtbefore_update_row (eins -> EINS)after_update_row (eins -> EINS)before_update_row (zwei -> ZWEI)after_update_row (zwei -> ZWEI)after_update_stmt
2 Zeilen wurden aktualisiert.
select *from trigger_test_table;
ID TEXT---------- ---------- 1 EINS 2 ZWEI 3 drei
SQL>
upper(...) wandelt eine Zeichenkette in Großbuchstabenum
Andreas Schmidt Trigger 9/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Unterscheidung der auslösenden Triggeraktion
create or replace TRIGGER before_updatebefore insert or update or delete on trigger_test_tablebegin if (INSERTING) then dbms_output.put_line('insert operation'); ELSIF (UPDATING) then dbms_output.put_line('update operation'); ELSIF (DELETING) then dbms_output.put_line('delete operation'); ELSE
raise_application_error(-20001, 'Das darf eigentlich nicht passieren!'); END IF;end;/
show errors
Andreas Schmidt Trigger 10/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Trigger - Einsatzgebiete
• ROW Trigger
• BEFORE INSERT/UPDATE:
• Um Spaltenwerte zu setzen oder zu transformieren• erweiterte Konsistenzchecks; eventuell verwerfen des Statements mit
raise_application_error(error_id, 'Text');
• AFTER INSERT/UPDATE: um weitere Aktionen anzuschucken
• BEFORE/AFTER DELETE
• zusätzliche Aktionen vor oder nach dem Löschen
• STATEMENT Trigger
• Auditing
• Checks
Andreas Schmidt Trigger 11/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Instead Of Trigger (1)
-- Szenario: Temperaturtabelle (in Fahrenheit) mit Zeitstempel und Ort der Messung-- View der die Temperatur in der Küche in Celsius ausgibt--
alter session set NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
create table temperature ( timestamp date, location varchar2(20), fahrenheit number(5,1), primary key (timestamp, location));
create or replace view kitchen_temperature (timestamp, celcius)
asselect timestamp, (fahrenheit-32) * 5.0/9.0 from temperature where location='kitchen';
Andreas Schmidt Trigger 12/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Instead Of Trigger (2)
create or replace trigger add_temperature_valueinstead of insert on kitchen_temperature
for each rowbegin insert into temperature values(:new.timestamp, 'kitchen', :new.celcius * 9.0/5.0 + 32);end;/show errors insert into temperaturevalues(sysdate-2/24, 'kitchen', 67);
insert into kitchen_temperature values(sysdate-1/24, 25.1);
-- Übung: Trigger für Update auf kitchen_temperature
aktiviert add_temperature_valuetrigger
Andreas Schmidt Trigger 13/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Mutating Table Problem
• Eine Tabelle wird als „Mutating Table“ bezeichnet, wenn
• Änderungen an dieser Tabelle den Trigger aktiviert haben oder
• diese Tabelle aufgrund von „ON DELETE ...“ Constraints eventuell modifiziert wer-den muss.
• Auf diese Tabellen darf von einem Row-Trigger aus nicht zugegriffen1 werden.
• Workarounds:
• auf diese Tabellen nicht zugreifen ;-)
• Temporäre Daten im ROW-Trigger ablegen und diese in einem AFTER-Statement-Trigger verarbeiten
• Trigger auf View definieren und mit „Instead of“ -Trigger arbeiten
1. sowohl lesend als auch schreibend
Andreas Schmidt Trigger 14/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
• Übung 1: Wenn ein Posten einer Bestellung gelöscht wird, dann soll eine Neu-numerierung der Positionen stattfinden (Szenario Tutorium 1, Übung 1)
• 1.Ansatzcreate or replace TRIGGER positionen_neu_berechnen0after delete on posten
for each rowbegin update posten set position=position-1 where bestellung_fk = :old.bestellung_fk and position > :old.position;end;/
• Resultat (beim Löschen eines Postens):ORA-04091: Tabelle SCAN0004.POSTEN wird gerade geõndert, Trigger/Funktion siehtdies m÷glicherweise nichtORA-06512: in "SCAN0004.POSITIONEN_NEU_BERECHNEN0", Zeile 3ORA-04088: Fehler bei der Ausf³hrung von Trigger'SCAN0004.POSITIONEN_NEU_BERECHNEN0'
Andreas Schmidt Trigger 15/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
• Lösung 1: Aufspalten in einen ROW- und einen Statement Trigger.
create table temp ( bestellung number references bestellung(id), geloeschte_position number);
create or replace TRIGGER positionen_neu_berechnen1after delete on postenfor each row
begin insert into temp values(:old.bestellung_fk, :old.position);end;/
Da man im Row Trigger nicht auf Datensätze der Tabelle Posten zugreifen
verschieben das auf den anschließenden Statement Triggerkann machen wir es einfach nicht, sondern
(da ist es erlaubt)
Andreas Schmidt Trigger 16/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
create or replace TRIGGER positionen_neu_berechnen2after delete on postendeclare cursor cur_position is select * from temp order by geloeschte_position desc;begin for data in cur_position loop update posten set position=position-1 where bestellung_fk = data.bestellung and position > data.geloeschte_position; end loop;
delete from temp;end;/
• Lösung 2: Mittels Instead of Trigger und View: siehe Beispiele zur Vorlesung
Auslesen der im Row-Triggerabgespeicherten Datensätzeund durchführen der UpdateOperation auf Tabelle Posten.
Anschließend löschen der Daten-sätze aus Tabelle temp.
Andreas Schmidt Trigger 17/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
weitere Trigger
• Data Definition Language Event Trigger:
• before / after create
• before / after grant
• before / after alter
• before / after drop
• ...
Andreas Schmidt Trigger 18/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Triggerbeispiel
create table person ( p_id number(8) primary key, vorname varchar2(60) not null, nachname varchar2(60) not null, geburtsdatum date not null, todesdatum date);
create table ist_verheiratet_mit ( ehemann_fk number(8) references person(p_id) on delete cascade, ehefrau_fk number(8) references person(p_id) on delete cascade, hochzeitsdatum date not null, trennungsdatum date, primary key(ehemann_fk, ehefrau_fk, hochzeitsdatum));
Andreas Schmidt Trigger 19/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Konsistenzchecks
• Heiraten darf man nur, wenn
• man mindestens 18 Jahre alt ist (Mindestalter)
• man nicht bereits verheiratet ist (keine Polygamie)
• ...
Andreas Schmidt Trigger 20/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
1. Check: Mindestalter
create or replaceTRIGGER bitte_nicht_mit_kindernbefore insert on ist_verheiratet_mitfor each rowdeclare cursor hochzeitsalter(p_hochzeitsdatum in date, er in number, sie in number) is select (p_hochzeitsdatum - p.geburtsdatum)/365 hochzeitsalter from person p where p.p_id in (er, sie);begin for data in hochzeitsalter(:new.hochzeitsdatum, :new.ehemann_fk, :new.ehefrau_fk) loop
if data.hochzeitsalter < 18 thenraise_application_error(-20002,'Mindestens einer der Lümmel ist zu jung um zu hei-
raten');end if;
end loop;end;/
Andreas Schmidt Trigger 21/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
2. Check: keine Polygamie
create or replaceTRIGGER bitte_keine_polygamiebefore insert on ist_verheiratet_mitfor each rowdeclare aktuelle_beziehungen number(1);
begin select count(*) into aktuelle_beziehungen from ist_verheiratet_mit
where (ehemann_fk=:new.ehemann_fk or ehefrau_fk=:new.ehefrau_fk) and (hochzeitsdatum < :new.hochzeitsdatum and (trennungsdatum > :new.hochzeitsdatum or trennungsdatum is null));
if aktuelle_beziehungen > 0 then raise_application_error(-20001,'Mindestens einer der Lümmel ist am '||
:new.hochzeitsdatum||' bereits verheiratet');end if;
end;/
Andreas Schmidt Trigger 22/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Ablauf
insert into person (p_id, vorname, nachname, geburtsdatum)values (1, 'Peter', 'Schulz', '20.10.1939');
insert into person (p_id, vorname, nachname, geburtsdatum)values (2, 'Heide', 'Lauer', '26.9.1940');
insert into person (p_id, vorname, nachname, geburtsdatum)values (3, 'Monika', 'Krieger', '2.2.1941');
insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum)values (1,2,'11.10.1954');
insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum)values (1,2,'11.10.1964');
update ist_verheiratet_mit set trennungsdatum='28.2.1970'where ehemann_fk=1 and ehefrau_fk=2 and hochzeitsdatum='11.10.1964';
insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum)values (1,3,'1.7.1968');
Andreas Schmidt Trigger 23/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Ablauf
-- Eingabe der 3 Personen wie vorherige Seite
SQL> insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum) 2 values (1,2,'11.10.1954');insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum)*FEHLER in Zeile 1:ORA-20002: Mindestens einer der Lümmel ist zu jung um zu heiratenORA-06512: in "SCAN0004.BITTE_NICHT_MIT_KINDERN", Zeile 15ORA-04088: Fehler bei der Ausführung von Trigger 'SCAN0004.BITTE_NICHT_MIT_KINDERN'
-- weitere statements wie auf vorheriger Folie ...
SQL> insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum) 2 values (1,3,'1.7.1968');insert into ist_verheiratet_mit (ehemann_fk, ehefrau_fk, hochzeitsdatum) *FEHLER in Zeile 1:ORA-20001: Mindestens einer der Lümmel ist am 01.07.68 bereits verheiratetORA-06512: in "SCAN0004.BITTE_KEINE_POLYGAMIE", Zeile 13ORA-04088: Fehler bei der Ausführung von Trigger 'SCAN0004.BITTE_KEINE_POLYGAMIE'
Andreas Schmidt Trigger 24/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
zum Üben ...
Mögliche Erweiterungen:
• Ausgabe, wer der Beteiligten die Regel verletzt
• der Partner sollte am Hochzeitstag noch leben ...
• Zusätzliches Attribut „ehestand“, der durch Eheschließung, Scheidung, Tod des Partners automatisch aktualisiert wird.
Andreas Schmidt Trigger 25/25
Fakultät für Informatik & Wirtschaftsinformatik
DB & IS II - SS 2019
Literatur
• Constraints and Triggershttp://www-db.stanford.edu/~ullman/fcdb/oracle/or-triggers.html
• Mutating Table Error on Cascading Deletehttp://www.akadia.com/services/ora_mutating_table_error.html