07.09.2009
17:02

Regeln in der Datenbank implementieren mit Hilfe von Triggern und User Defined Functions

Rodney Krick, Senior Consultant und Dozent bei aformatik

von Rodney Krick
Hier ist etwas, das wir vor einiger Zeit auf Anforderung eines Kunden implementiert haben. Es handelte sich um eine Zoll-Applikation und für eine Entität unseres Datenmodells musste gewährleistet werden, dass ein bestimmtes Attribut immer den letzten Tag des Quartals beinhaltet.
Und so sah die Spezifikation aus: wir bekommen Artikeldaten über eine Schnittstelle. Die "Waren" bleiben ab Wareneingang genau zwei Jahre lang unter Zollüberwachung. Was wir hier zeigen ist zwar DB2 Code, aber die gleiche Funktionalität kann man bei fast jedem RDBMS implementieren.
Solche Art von Regeln sollte man eigentlich immer in der Datenbank implementieren. Damit ist garantiert, dass das Attribut immer regelkonform ist.
Und wie macht man das? Der erste Schritt ist die Ermittlung des letzten Tages im Quartal und das machen wir mit einer User Defined Function (UDF) und einem naiven Algorithmus.

 

CREATE FUNCTION END_QUARTER(myDate DATE)
LANGUAGE SQL
RETURNS DATE
RETURN
        (CASE QUARTER(myDate)
            WHEN 1 THEN DATE('31.03.' || CHAR(YEAR(myDate)))
            WHEN 2 THEN DATE('30.06.' || CHAR(YEAR(myDate)))
            WHEN 3 THEN DATE('30.09.' || CHAR(YEAR(myDate)))
            WHEN 4 THEN DATE('31.12.' || CHAR(YEAR(myDate)))
           );

 

Diese Funktion bekommt als Parameter ein Datum (myDate), ermittelt das Quartal anhand einer Standardfunktion (QUARTER()) und gibt den letzten Tag des Quartals des eingegebenen Datums zurück. Wir setzen einfach voraus, dass der letzte Tag eines Quartals relativ stabil bleibt, d.h. wir erwarten keine Änderung in den nächsten Jahren ;-)

Wenn wir nun eine neue Entität in die Tabelle hinzufügen, verwenden wir die neue Funktion um das gewünschte Datum zu ermitteln.

Beispiel:

 

CREATE TABLE TESTTAB
        (...
        , BASIS_DATE DATE
        , END_DATE DATE
        , ...)
;

INSERT INTO TESTTAB
        (...
        , BASIS_DATE DATE
        , END_DATE DATE
        , ...)
VALUE
        (...
        , :some_date
        , END_QUARTER(DATE(:some_date) + 2 YEARS)
        , ...)
;

 

Beim Hinzufügen eines BASIS_DATA gleich 2009.09.04, bekommen wir ein END_DATE gleich 2011.09.30.

Jetzt wollen wir auch sicherstellen, dass diese "Spalte" nur den letzten Tag eines Quartals erlaubt. Das machen wir mit zwei Triggern:

 

CREATE TRIGGER BIT_TESTTAB
NO CASCADE BEFORE INSERT ON TESTTAB
REFERENCING NEW AS NEWTAB
FOR EACH ROW
MODE DB2SQL
SET NEWTAB.END_DATE = END_QUARTER(NEWTAB.END_DATE);


CREATE TRIGGER BUT_TESTTAB
NO CASCADE BEFORE UPDATE ON TESTTAB
REFERENCING NEW AS NEWTAB
FOR EACH ROW
MODE DB2SQL
SET NEWTAB.END_DATE = END_QUARTER(NEWTAB.END_DATE);

 

Wird jetzt ein Datum in diese Spalte hinzugefügt oder modifiziert, wird der letzte Tag des Quartals für dieses Datum gespeichert. Das heißt, bei Inserts und Updates wird die neue Regel berücksichtigt.


Danke fürs Vorbeischauen!

Rodney Krick

  •  
  • 3 Kommentar(e)
  •  
Roman Seibold
28.09.2009
21:42
CONCAT und CHAR

Vielleicht könnte Rodney mir noch in einer Replik darauf antworten, was genau im Ausdruck DATE('31.03.' || CHAR(YEAR(myDate)) der hintere Teil macht. Ist "||" der Konkatenationsoperator (in Java bedeutet diese Zeichenfolge das bedingte Oder)? Ist es korrekt zu vermuten, dass wenn myDate = "28.03.09" dann ergibt der CASE-Ausdruck "31.09.09"? Was genau macht darin dann CHAR? Steht das für nur ein Zeichen? Fragen über Fragen. Grüße, Roman

Rodney Krick
29.09.2009
09:48
CONCAT und CHAR

Hallo Roman,

|| ist der Konkatenationsoperator. Es gibt auch eine SQL Scalar Function (CONCAT(s,s)) die genau das Gleiche zurückliefert.
CHAR ist auch eine SQL Funktion. Wird hier verwendet weil die Operatoren bei der Konkatenierung "Strings" sein müssen (CHAR oder VARCHAR). In dem Fall, wird ein YEAR (SMALLINT) in einem CHAR konvertiert und das Ergebnis mit dem letzten Tag des Quartals als Parameter für die Funktion DATE() verwendet.
Wenn myDate = "29.03.09" ist, dann ergibt der CASE-Ausdruck "31.03.2009".
I hope this helps :-)
Gruß,
Rodney

WP Themes
19.01.2010
18:05
Delivered Wp Themes

Good post and this enter helped me alot in my college assignement. Thanks you as your information.

Mein Kommentar

Zurück