Von der passiven zur aktiven Datenbank II • • • Trigger Views Prozerdurale SQL-Erweiterungen Konzept der aktiven DB • ECA-Prinzip: – Event, Condition, Action Spezifizierte DB-Zustände Ereignis ggf. automatische Aktion • Ereigniskonzept: – beliebig viele unabhängige ECA-Spezifikationen pro Ereignis (c) schmiedecke 06 DB11- Aktive DB 2 Aktionsspezifikation in SQL • Constraints: Assertions, Checks – deskriptiv "Aktion" besteht im Zurückweisen einer Operation – Bedingungen, unter denen DML-Operationen zurückgewiesen werden • Referentielle Aktionen – operational – Reparaturmaßnahmen bei Verletzung der referentiellen Integrität • Trigger – operational – Mit DML-Operationen verknüpfte frei programmierbare Aktionen (c) schmiedecke 06 DB11- Aktive DB 3 Integritätssicherung • • • • DB-Aktionen sollten der Integritätssicherung dienen. Es ist in der Regel nicht sinnvoll, die (gesamte) Geschäftslogik durch DBAktionen zu implementieren! DB als gemeinsamer Datenbestand verschiedener Anwendungen mit unterschiedlicher Geschäftslogik – Integrität als gemeinsame Eigenschaft. Evtl. Subsystem zur Implementierung gemeinsamer Geschäftsregeln mehrerer Anwendungen. Anwendung2 Anwendung1 Anwendung3 Subsystem Anwendung4 DB (c) schmiedecke 06 DB11- Aktive DB 4 Trigger • Aktion aufgrund der Zustandsänderung einer Tabelle - lokal angesiedelt - ausgelöst durch das DBMS - nicht beschrieben, sondern "programmiert" • Wann? - Aufgrund von UPDATE, INSERT oder DELETE - Vor oder nach der Änderung (BEFORE / AFTER) • Wie? - einmalig - oder zeilenweise (FOR EACH ROW) - dann Zugriff auf alte und neue Werte: REFERENCING OLD AS alt NEW AS neu • Was? - Frei programmierbare SQL-Anweisung - Frei programmierbare Anweisungen in der prozeduralen SQL-Erweiterung (SQL-1999: SQL/PSM Oracle: PL/SQL oder SQLJ, MySQL: T-SQL) (c) schmiedecke 06 DB11- Aktive DB 5 Trigger-Syntax (SQL-1999, auch Oracle) CREATE [OR REPLACE] TRIGGER trigger-name { BEFORE | AFTER } trigger-event [ OF spalten-name ON tab-name [ FOR EACH ROW [ WHEN trigger-condition ] DECLARE var-decls BEGIN trigger-body END trigger-name ALTER TRIGGER trigger-name { ENABLE | DISABLE }; DROP TRIGGER trigger-name; (c) schmiedecke 06 DB11- Aktive DB 6 Trigger • Einfache SQL-Trigger: – Trigger-Body reines SQL – evtl. mit Variablen • Instead-Of-Trigger: – DML-Operationen auf Views – oft reines SQL • Programm-Trigger: – Trigger-Body in prozeduraler SQL-Erweiterung – oft Aufruf von Strored Procedures – oft Ereignisquelle für Geschäftslogik (c) schmiedecke 06 DB11- Aktive DB 7 "Host-Variablen" • Einige Variablen aus der Laufzeitumgebung stehen innerhalb von Triggern zur Verfügung, • z.B. der alte und neue Zustand der aktuellen Zeile (nur bei Option "for each row"!) • Sie heißen OLD und NEW • Zugriff innerhalb von SQL mit Doppelpunkt: :OLD :NEW • OLD und NEW sind Tupel. • Zugriff auf einzelne Spaltenwerte :NEW.strasse • Umbenennung mit "Referencing OLD as ALT" (c) schmiedecke 06 DB11- Aktive DB 8 Trigger zur Wertanpassung • Jeder Verkauf erhöht die Vertreterprovision um 0.1%: CREATE OR REPLACE TRIGGER prov_trigger AFTER INSERT ON aufkopf FOR EACH ROW BEGIN UPDATE vert SET vert.prov = vert.prov+0.1 WHERE vert.vertnr = (SELECT vertnr from kdst, vert WHERE kdst.vertreter = vert.vertnr AND kdst.kdnr = :NEW.kdnr); END; (c) schmiedecke 06 DB11- Aktive DB 9 Variablen • Beliebige Variablen deklarierbar • Typ: Standardtypen oder Zeilen- und Spaltentypen: DECLARE text Varchar(10); zeile konserven%rowtype; gruppe konserven%bgtype; • Verwendung mit INSERT INTO • oder Zuweisung := (c) schmiedecke 06 DB11- Aktive DB 10 Trigger zur Wertanpassung - 2 • Jeder Verkauf erhöht die Vertreterprovision um 0.1% - Version 2: CREATE OR REPLACE TRIGGER prov_trigger2 AFTER INSERT ON aufkopf FOR EACH ROW DECLARE vn NUMBER; BEGIN SELECT vertnr INTO vn FROM kdst, vert WHERE kdst.vertreter = vert.vertnr AND kdst.kdnr = :NEW.kdnr; UPDATE vert SET vert.prov = vert.prov+0.1 WHERE vert.vertnr = vn; END; (c) schmiedecke 06 DB11- Aktive DB 11 Trigger für Zusatzeintrag • Jede neue Konserve der Blutgruppe AB- soll zusätzlich in die Tabelle "abneg" eingetragen werden: • CREATE TRIGGER trig_abneg_insert AFTER INSERT ON konserve REFERENCING NEW AS neu FOR EACH ROW WHEN :neu.blutgr = 'AB-' BEGIN INSERT INTO abneg VALUES (:neu.kons_id, :neu.datum); -- zusätzlich eine PLSQL-Anweisung: dbms_output.put_line('AB neg inserted: '|| :neu.datum); END; • SET SERVEROUTPUT ON -- damit der Output angezeigt wird…. (c) schmiedecke 06 DB11- Aktive DB 12 Trigger für Zeitstempel • Jeder Eintrag in die Konserventabelle erhält einen Zeitstempel • CREATE TRIGGER stempel BEFORE INSERT ON konserve REFERENCING NEW AS neu FOR EACH ROW BEGIN :neu.zeitstempel := SYSDATE; END; (c) schmiedecke 06 DB11- Aktive DB 13 Löschen ganzer Tabellen • DELETE FROM tabelle; löst alle DELETE-Trigger aus • Umgehen mit DDL-Anweisungen anstelle von DMLAnweisungen: • DROP TABLE tabelle; Create TABLE tabelle ...; • TRUNCATE TABLE tabelle; (c) schmiedecke 06 DB11- Aktive DB 14 Sequences in Oracle • • • • Oracle kennt kein Auto-Increment stattdessen Sequences Vorteil: tabellenübergreifend nutzbar Schritte: – – – – Sequence spezifizieren und erzeugen Sequence initialisieren Werte lesen Sequence weiterschalten (c) schmiedecke 06 DB11- Aktive DB 15 Sequenz erzeugen • CREATE SEQUENCE sequence_name [ MINVALUE value ] [ MAXVALUE value ] [ START WITH value ] [ INCREMENT BY value ] [ CYCLE ] [ CACHE value ] [ ORDER ] ; example: • CREATE SEQUENCE id_seq MINVALUE 0 START WITH 10 INCREMENT BY 10 CACHE 20; (c) schmiedecke 06 DB11- Aktive DB 16 Sequenz benutzen • 2 Pseudospalten in Pseudotabelle "DUAL": – sequenz.currval - enthält letzten vergebenen Wert – sequenz. nextval - erzeugt und liefert Folgewert - und initialisiert die Sequenz • SELECT id_seq.nextval FROM dual; -- initialis. SELECT id_seq.currval, id_seq.nextval FROM dual; CURRVAL NEXTVAL 10 20 • INSERT INTO spender (id_seq.nextval, 'Mayr', 'Sepp', … ); (c) schmiedecke 06 DB11- Aktive DB 17 Trigger für Auto-PK CREATE TRIGGER trg_spender_id BEFORE INSERT ON spender FOR EACH ROW BEGIN SELECT id_seq.nextval INTO :NEW.spender_id FROM DUAL; END; (c) schmiedecke 06 DB11- Aktive DB 18 Views • Schein-Relationen (vgl. Scheinriese bei Jim Knopf ) • Realisierung externer Sichten • Gespeicherte benannte SELECT-Anweisungen, die (fast) wie Tabellen benutzt werden können • Nicht als Relation gespeichert, sonder immer wieder frisch erzeugt! • Komplementärbegriff: Basisrelation • Vorteile: – Implementierungs-Kapselung (Verbergen der Struktur) – Komplexitätskapselung bei Queries (c) schmiedecke 06 DB11- Aktive DB 19 Definition und Benutzung einer View CREATE VIEW view_name AS SELECT columns FROM tables WHERE predicates; Beispiel: CREATE VIEW terminbuch AS SELECT termin, platz, name AS "Spender" FROM termin, spender WHERE termin.spender_id = spender.spender_id ; SELECT * FROM terminbuch WHERE platz = P AND termin BETWEEN 01/06/06 AND 01/0706; Ändern einer VIEW : CREATE OR REPLACE VIEW view_name AS SELECT columns FROM table WHERE predicates; (c) schmiedecke 06 DB11- Aktive DB 20 DML auf Views: Instead-of-Trigger • Generell keine DML-Operationen auf Views • Erlaubt bei 1-Tabellen-Projektionen • Instead of – Trigger – ersetzt scheinbare DML-Anweisung auf einer View – durch DML-Anweisungen auf den Basisrelationen (c) schmiedecke 06 DB11- Aktive DB 21 Trigger-Syntax CREATE [OR REPLACE] TRIGGER trigger-name { BEFORE | AFTER | INSTEAD OF } trigger-event ON tab-name [ FOR EACH ROW [ WHEN trigger-condition ] ] BEGIN trigger-body END trigger-name ALTER TRIGGER trigger-name DISABLE; DROP TRIGGER trigger-name; (c) schmiedecke 06 DB11- Aktive DB 22 INSTEAD-OF-TRIGGER zur Erinnerung: CREATE VIEW terminbuch AS SELECT termin, platz, name AS "Spender" FROM termin, spender WHERE termin.sp_id = spender.sp_id ; CREATE TRIGGER trg_ins_termin INSTEAD OF INSERT ON terminbuch FOR EACH ROW - - um :NEW zur Verfügung zu haben BEGIN INSERT INTO termin (datum, platz, sp_id) VALUES (:NEW.termin, :NEW.platz, ( SELECT sp_id FROM spender WHERE sp_name = name) END trg_ins_termin; (c) schmiedecke 06 DB11- Aktive DB 23 Verwendung von Views • Zur Vereinfachung häufig benutzter Abfragen • Zur Kapselung der Basisrelationen: – als Schnittstelle für graphische Oberflächen – als Schnittstelle für Kommunikationsprozesse, die Daten aus der DB lesen oder dort ablegen – oder zur Anpassung von Standard-Datenbanken an Projektspezifika (Verschmelzung mit Ergänzungsrelationen) • Vorteil: – Schnittstellenabhängige Software wird von Änderungen der Basisrelationen abgeschirmt (c) schmiedecke 06 DB11- Aktive DB 24 Prozedurale SQL-Erweiterung • SQL ist (bewusst) begrenzt • Prozedurale Vollständigkeit manchmal nötig, oft erwünscht • 2 Möglichkeiten: – SQL-Anweisungen in Programmiersprache einbetten, DBInteraktion während der Programmausführung embedded SQL JDBC, SQLJ, ADO, ... – Prozedurale Anteile in SQL einfügen, Ausführung im DBMS prozedurale Erweiterungen, SQL/PSM (seit SQL-1999) (persistent stored modules) in Oracle PL/SQL seit ... ? (c) schmiedecke 06 DB11- Aktive DB 25 PL/SQL • ORACLE-DB-Programmiersprache • sehr einfach zu lernen • Grundstruktur eines PL/SQL-Skripts: DECLARE variablen BEGIN anweisungen EXCEPTION fehlerbehandlungs-anweisungen END • Weblinks: http://www-db.stanford.edu/~ullman/fcdb/oracle/or-plsql.html ---sehr kompakte Syntax-Beschreibung http://www.dbai.tuwien.ac.at/education/dbs/folien/plsql.pdf ------umfassende Einführung mit Beispielen (c) schmiedecke 06 DB11- Aktive DB 26 MySQL • • • • ... Trigger erst ab MySQL 5, ... erst ab Version 5.1.4 ohne Super-Rechte definierbar. Sprache ziemlich genau SQL/PSM Beschreibung (bisher nur Englisch) http://dev.mysql.com/doc/refman/5.0/en/stored-procedures.html (c) schmiedecke 06 DB11- Aktive DB 27 PL/SQL • die üblichen Kontrollstrukturen • Datentypen wie in ORACLE • am besten Variablentypen genau an DB-Typen anpassen: DECLARE akt_blutgr konserve.blutgr%TYPE; akt_kons konserve%ROWTYPE; • Laden von Daten in PL/SQL-Variablen SELECT col1, col2 INTO var1, var2 FROM tabelle WHERE bedingung; (c) schmiedecke 06 DB11- Aktive DB 28 Trigger zur Alters-Überprüfung • • • • • Spender über 100 Jahre dürfen nicht eingetragen werden. Zusätzliche Spalte midage soll eine 1 erhalten, falls Spender zwischen 20 und 50, sonst eine 0. Definiert mit Typ NUMBER(1) Trigger zur Altersüberprüfung CREATE OR REPLACE TRIGGER age_trigger BEFORE INSERT ON konserve FOR EACH ROW BEGIN IF :NEW.alter BETWEEN 20 AND 50 THEN :NEW.midage := 1 ELSEIF alter > 100 THEN :NEW.midage := 999 -- illegal! ELSE :NEW.midage := 0 ENDIF; END; (c) schmiedecke 06 DB11- Aktive DB 29 Exceptions • Bessere Lösung mit Exceptions • Dem Selbststudium überlassen... (s. http://www.dbai.tuwien.ac.at/education/dbs/folien/plsql.pdf) • CREATE OR REPLACE TRIGGER age_trigger BEFORE INSERT ON konserve FOR EACH ROW DECLARE age_exception EXCEPTION; BEGIN IF :NEW.alter BETWEEN 20 AND 50 THEN :NEW.midage := 1 ELSEIF alter > 100 THEN RAISE age_exception ELSE :NEW.midage := 0 ENDIF; END; (c) schmiedecke 06 DB11- Aktive DB 30 Trigger-Verwendung • Semantische Integrität: – Berechnung abgeleiteter Attribute – z.B. Summenspalte mitführen (Achtung: nur Delta addieren, nicht neu summieren ) • In ORACLE: AUTO INCREMENT für Primärschlüssel • Projekt-Verwaltung • Aufruf externer Funktionen • Datenmanipulation auf Views – Eintrag von Datum und Autor bei insert und update – Logging (Mitschreiben bestimmter DB-Aktionen) – z.B. Palettenwechsel, Nachbestellungen, … – Grund: SQL-Befehle werden oft dynamisch zusammengesetzt – im Programmcode unauffindbar – instead of – Trigger (c) schmiedecke 06 nächstes Kapitel DB11- Aktive DB 31 ! " # $%