• Keine Ergebnisse gefunden

Fakultät für Informatik & Wirtschaftsinformatik Datenbanken u. Informationssysteme II. Rec. on? Trigger. ndreas Schmidt Trigger 1/26

N/A
N/A
Protected

Academic year: 2022

Aktie "Fakultät für Informatik & Wirtschaftsinformatik Datenbanken u. Informationssysteme II. Rec. on? Trigger. ndreas Schmidt Trigger 1/26"

Copied!
26
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Trigger

Rec. on?

(2)

Trigger

• Konzept, um automatisch auf vordefin- ierte Ereignisse in der Datenbank zu reagieren

• Trigger sind mit Datenbanktabelle verknü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 (State- ment Trigger)

• auf jeden einzelnen betroffenen Datensatz (Row Trigger)

Rec. on?

(3)

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 Views 1

• Vordefinierte Variablen :new und :old für den Zugriff auf die alten/neuen Werte (nur bei ROW, INSTEAD OF-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 Trigger-

code

(4)

Trigger Beispiele (ROW)

create or replace trigger example_row_trigger after update of population on city

for each row begin

dbms_output.put_line('Bevölkerungszuwachs in '||:old.name||

' von '||:old.population||' auf '||:new.population);

end;

/

SQL> set serveroutput on SQL> update city

set population=round(population*1.05) where country='D';

Bevölkerungszuwachs in Bremen von 549182 auf 576641 Bevölkerungszuwachs in Stuttgart von 588482 auf 617906 Bevölkerungszuwachs in Potsdam von 138268 auf 145181 Bevölkerungszuwachs in Wiesbaden von 266081 auf 279385 Bevölkerungszuwachs in Schwerin von 118291 auf 124206 ...

(5)

Trigger Beispiele (STATEMENT)

create or replace trigger example_statement_trigger after delete on city

begin

dbms_output.put_line('User '||user()||

' hat ein DELETE Statement auf Tabelle city durchgeführt');

end;

/

show errors

SQL> delete city

where population < 100000;

User SCAN0004 hat ein DELETE Statement auf Tabelle city durchgeführt 184 Zeilen wurden gelöscht.

SQL>

(6)

Trigger Beispiele (Check)

create or replace trigger check_establishment_time before insert on city

begin

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 city (name, country, population) values('Smifftown', 'D', 142252352);

insert into city (name, country, population) *

FEHLER in Zeile 1:

ORA-20001: Städte dürfen nur nachmittags gegründet werden ORA-06512: in "SMIFF.CHECK_ESTABLISHMENT_TIME", Zeile 3

ORA-04088: Fehler bei der Ausf³hrung von Trigger 'SMIFF.CHECK_ESTABLISHMENT_TIME'

(7)

Abarbeitungsreihenfolge

create table trigger_test_table ( id number primary key,

text varchar2(10) );

create or replace TRIGGER before_update before update on trigger_test_table begin

dbms_output.put_line('before_update_stmt');

end;

/

create or replace TRIGGER after_update after update on trigger_test_table begin

dbms_output.put_line('after_update_stmt');

end;

/

create or replace TRIGGER before_update_row before update on trigger_test_table

for each row begin

dbms_output.put_line('before_update_row ('||

:old.text||'->'||:new.text||')');

end;

/

create or replace TRIGGER after_update_row after update on trigger_test_table

for each row begin

dbms_output.put_line('after_update_row ('||

:old.text||'->'||:new.text||')');

end;

/

(8)

Abarbeitungsreihenfolge

insert into trigger_test_table values(1, 'eins');

insert into trigger_test_table values(2, 'zwei');

insert into trigger_test_table values(3, 'drei');

set serveroutput on

update trigger_test_table set text=upper(text) where id < 3;

before_update_stmt

before_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ßbuchstaben um

(9)

Unterscheidung der auslösenden Triggeraktion

create or replace TRIGGER before_update

before insert or update or delete on trigger_test_table begin

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

(10)

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

(11)

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) as

select timestamp, (fahrenheit-32) * 5.0/9.0 from temperature

where location='kitchen';

(12)

Instead Of Trigger (2)

create or replace trigger add_temperature_value instead of insert on kitchen_temperature

for each row begin

insert into temperature

values(:new.timestamp, 'kitchen', :new.celcius * 9.0/5.0 + 32);

end;

/

show errors

insert into temperature

values(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_value trigger

kann auch weggelassen werden, da

Instead-Of Trigger, immer auf Datensatz Basis arbeiten

(13)

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 werden muss.

• Auf diese Tabellen darf von einem Row-Trigger aus nicht zugegriffen 1 werden.

• Workarounds:

• auf diese Tabellen nicht zugreifen ;-)

• Innerhalb des ROW-Triggers temporäre Daten ablegen und diese in einem AFTER-Statement-Trigger verarbeiten

• Trigger auf View definieren und mit „Instead of“ -Trigger arbeiten

(14)

Beispiel zu Mutating Table Problem

• Aus Tutorium 1 (PL/SQL): Wenn ein Posten einer Bestellung gelöscht wird, dann soll eine Neunumerierung der Positionen stattfinden (Szenario Tutorium 1, Übung 1)

create table posten (

bestellung_fk number not null references bestellung (id)

on delete cascade,

artikel_fk number not null references artikel(id)

on delete cascade, position number not null,

anzahl number check (anzahl > 0),

constraint CONS_KEINE_GLEICHEN_ARTIKEL

unique(bestellung_fk, artikel_fk) );

Tabelle 1: Posten

bestellung_fk artikel_fk position anzahl

... ... ... ...

5 4 1 1

5 7 2 10

5 21 3 2

5 8 4 1

6 1 1 1

6 21 2 20

... ... ... ...

(15)

Beispiel zu Mutating Table Problem

• 1.Ansatz

create or replace TRIGGER positionen_neu_berechnen0 after delete on posten

for each row begin

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 sieht dies m÷glicherweise nicht

ORA-06512: in "SCAN0004.POSITIONEN_NEU_BERECHNEN0", Zeile 3 ORA-04088: Fehler bei der Ausf³hrung von Trigger

'SCAN0004.POSITIONEN_NEU_BERECHNEN0'

(16)

Beispiel zu Mutating Table Problem

• 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_berechnen1 after delete on posten

for 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 Trigger kann machen wir es einfach nicht, sondern

(da ist es erlaubt)

(17)

Beispiel zu Mutating Table Problem

create or replace TRIGGER positionen_neu_berechnen2 after delete on posten

declare

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-Trigger abgespeicherten Datensätze und durchführen der Update Operation auf Tabelle Posten.

Anschließend löschen der Daten- sätze aus Tabelle temp.

(18)

weitere Trigger

• Data Definition Language Event Trigger:

• before / after create

• before / after grant

• before / after alter

• before / after drop

• ...

(19)

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)

);

(20)

Konsistenzchecks

• Heiraten darf man nur, wenn

• man mindestens 18 Jahre alt ist (Mindestalter)

• man nicht bereits verheiratet ist (keine Polygamie)

• ...

(21)

1. Check: Mindestalter

create or replace

TRIGGER bitte_nicht_mit_kindern

before insert on ist_verheiratet_mit for each row

declare

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 then

raise_application_error(-20002,'Mindestens einer der Lümmel ist zu '||

'jung um zu heiraten');

end if;

end loop;

end;

(22)

2. Check: keine Polygamie

create or replace

TRIGGER bitte_keine_polygamie

before insert on ist_verheiratet_mit for each row

declare

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;

/

(23)

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');

(24)

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 heiraten ORA-06512: in "SCAN0004.BITTE_NICHT_MIT_KINDERN", Zeile 15

ORA-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 verheiratet ORA-06512: in "SCAN0004.BITTE_KEINE_POLYGAMIE", Zeile 13

ORA-04088: Fehler bei der Ausführung von Trigger 'SCAN0004.BITTE_KEINE_POLYGAMIE'

(25)

zum Üben ...

Mögliche Erweiterungen:

• Ausgabe, welcher der Beteiligten die Regel verletzt

• der Partner sollte am Hochzeitstag noch leben ...

• Zusätzliches Attribut „ehestand“ für eine Person, das durch Eheschließung, Schei-

dung, Tod des Partners automatisch aktualisiert wird.

(26)

Literatur

• Constraints and Triggers

http://www-db.stanford.edu/~ullman/fcdb/oracle/or-triggers.html

• Mutating Table Error on Cascading Delete

http://www.akadia.com/services/ora_mutating_table_error.html

Referenzen

ÄHNLICHE DOKUMENTE

Um einen Schmitt-Trigger zu bekommen, werden die beiden Eingänge vertauscht, sodass man die Schaltung nach ABB. Der Eingang E wird mit dem Frequenzgenerator verbunden. Über

Kunden dürfen nur gelöscht werden, wenn sie keine Waren mehr bestellt haben. Der Preis eines Grundnahrungsmittels darf innerhalb von drei Jahren höchstens um

The edi- tors of Trigger #3 are looking for projects, essays, contributions that clearly name conflicts of interest, that show attitudes and present positions that examine

Folding States of Nascent Polypeptides Influence TF Associa- tion with Ribosomes—The observed decrease in the association rates for longer chains or partially folded domains

In this study, we show that (i) TF recognizes aromatic and basic amino acid residues in peptide substrates, (ii) TF binding to peptides does not depend on the presence of prolines,

TF as well as the recombinant version of TF with an addi- tional C-terminal His 6 tag elute from SEC columns within smaller volumes than expected from their molecular mass of 48

The binding sites con tain nonpolar residues form ing hydrophobic pockets that bind to hydrophobic peptide stretches of 6 to 10 residues in substrate proteins.. The binding sites have

The task of event trigger labeling is typi- cally addressed in the standard supervised setting: triggers for each target event type are annotated as training data, based on