25
ndreas Schmidt Trigger 1/25 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - SS 2019 Trigger

Trigger - smiffy.desmiffy.de/DB-IS-II/folien/v12-trigger-example.pdf · • Auf diese Tabellen darf von einem Row-Trigger aus nicht zugegriffen1 werden. • Workarounds: • auf diese

  • 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