Kaufmännische Software für Handel, Handwerk und Produktionsbetriebe
Trigger stellen ein elegante Methode dar, eigene Funktionen aber auch Änderungen an Abläufen, in die Warenwirtschaft EULANDA® zu integrieren.
Trigger sind eine Sonderform von gespeicherten Prozeduren. Sie können nahezu beliebige SQL-Befehle enthalten und werden vom SQL-Server automatisch bei bestimmten Datenbankoperationen (Einfügen, Ändern, Löschen von Datensätzen) aufgerufen.
Die Möglichkeit im Trigger Fehlermeldungen auszugeben, die der Endanwender angezeigt bekommt und die Möglichkeit die ursprünglichen Datenbankoperationen, die den Trigger ausgelöst haben, wieder vollständig rückgängig (Rollback) zu machen, eröffnet ein weites Spektrum an Anwendungsmöglichkeiten.
Einige der möglichen Aufgaben für einen Trigger sind:
Trigger werden einzelnen Tabellen zugeordnet. Und zu jedem Trigger wird festgelegt , bei welchen Operationen er ausgelöst (engl. triggered) werden soll. Diese Operationen sind:
INSERT, UPDATE und DELETE
Ein einzelner Trigger kann auch mehrere dieser Operationen gleichzeitig überwachen. Aber der selbe Trigger kann nicht bei mehreren Tabellen hinterlegt werden, auch wenn die verwendeten Tabellenspalten gleich lauten.
EULANDA® definiert bereits zu fast allen Tabellen eigene Trigger, die die Business-Logik abbilden. Microsoft SQL-Server® hat aber die angenehme Eigenschaft beliebig viele Trigger pro Tabelle zu hinterlegen. Ihnen als Entwickler sind also in dieser Hinsicht keine Grenzen in Punkto Erweiterbarkeit gesetzt.
Damit sich Benutzer-Trigger nahtlos in EULANDA® integrieren und nicht zu Fehlfunktionen führen müssen allerdings einige Dinge beachtet werden.
Beispiel für einen Benutzer-Trigger
CREATE TRIGGER TR_USER_AF_INSUPD_StatusPruefung ON Auftrag
FOR INSERT, UPDATE
AS
/* Dies muss der erste Befehl in einem Trigger sein */
SET NOCOUNT ON
/* Hier fangen die eigentlichen Trigger-Befehle an*/
Bis auf sehr wenige Ausnahmen möchte man in einem Trigger nur eine eingeschränkte Anzahl von Spalten überwachen. Transact-SQL liefert mit der Funktion UPDATE(spaltenname) die Möglichkeit die geänderten Spalten zu ermitteln. Kleiden Sie Ihre Trigger-Befehle stets in einen Bedingungs-Block ein, der alle gewünschten Felder enthält:
IF UPDATE(Status) OR UPDATE(Objekt) OR UPDATE (Datum) BEGIN /* Ihre Trigger Befehle */ END
Hinweis:
Die UPDATE-Funktion liefert in DELETE-Triggern immer False zurück.
Minimieren Sie bzw. Optimieren Sie SELECT oder INSERT Befehle. Legen Sie ggf. Indizes in den den entsprechenden Tabellen an, um die Ausführungszeit zu verkürzen.
Nur weil die Funktion UPDATE(spaltenname) True liefert, muss die Spalte nicht auch geändert worden sein. Z.B. ändert der Befehl
UPDATE Adresse SET RabattGr = 'A' WHERE RabattGr = 'A'
nicht die Rabattgruppe aber UPDATE spricht trotzdem an. Wenn ein aufwendiger SQL-Befehl von einer „echten“ Änderung der Spalte abhängt, sollten Sie weitere Prüfungen vorsehen. Folgender Befehl erzeugt beispielsweise eine temporäre Tabelle mit den Adress-IDs, die wirklich geändert wurden:
DECLARE @t TABLE (id int)
INSERT @t SELECT i.id
FROM inserted i, deleted d
WHERE i.id = d.id AND i.RabattGr <> d.RabattGr
In diesem Beispiel wird beim Ändern der Auftragspositionen überprüft, ob noch ein positiver Ertrag vorliegt. Wenn das nicht der Falls ist, wird eine Fehlermeldung ausgegeben und die Änderung verworfen (Hinweis: diese Überprüfung könnte auch mit einem CHECK-CONSTRAINT durchgeführt werden).
CREATE TRIGGER TR_USER_AFP_INSUPD_Ertrag ON AuftragPos
FOR INSERT, UPDATE
AS
SET NOCOUNT ON
IF ( UPDATE(VkRab) OR UPDATE(Menge) OR UPDATE(PreisEH) )
BEGIN
IF EXISTS (SELECT * FROM inserted
WHERE (Menge > 0) AND (Ertrag < 0) ) BEGIN
RAISERROR('[VENDOR:USER][ADRESS:USER]Die
Marge zu gering ist!', 16,1)
ROLLBACK
END
END
Dieser Trigger protokolliert Änderungen am Datum bzw. Bestellstatus des Auftrags. Hierbei werden nur Aufträge berücksichtigt, die älter als eine Stunde sind. Die Informationen werden im SQL-Server-Protokoll festgehalten. Dieses kann im SQL-Enterprise-Manager oder im Windows-Explorer als Textdatei eingesehen werden.
CREATE TRIGGER TR_USER_AF_UPD_Datum ON Auftrag
FOR UPDATE
AS
SET NOCOUNT ON
IF UPDATE(Datum) OR UPDATE(BestellStatus)
BEGIN
/* Überprüfen, ob Aufträge existieren, die älter als eine
** Stunde sind */
IF EXISTS(SELECT * FROM inserted
WHERE DATEDIFF(hour,CreateDate,GETDATE())>1 )
BEGIN
/* Deklaration der verwendeten Variablen */
DECLARE @userid int, @nr int, @count int
/* Ermitteln der Auftragsnummer und der Anzahl der
** geänderten Aufträge. Falls mehrere Aufträge betroffen sind
** wird in diesem Beispiel nur die kleinste Nummer ermittelt. */
SELECT @nr = MIN(KopfNummer), @count = COUNT(*) FROM inserted
/* Erzeugen eines Eintrags in Tabelle cnProesses
** mit allen Angaben zum Benutzer und Arbeitsplatz
** an dem der Befehl ausgeführt wird */
EXEC cn_UserId @userid OUT
/* Eintrag einer Fehlermeldung in das SQL-Server-Protokoll
** Der Schweregrad ist 1. Dadurch wird der Fehler
** nicht an EULANDA weitergegeben */
RAISERROR('Datum/BestellStatus in %d Auftragsposition(-en)
geändert (Auftrag #%d)
von Prozess %d (siehe Tabelle cnProcesses für Details)',
1,1, @count, @nr, @userid) WITH LOG
END
END
Folgendes SQL-Skript zeigt, dass ein UPDATE-Befehl nicht auch unbedingt Zeilen ändern muss. Für Trigger-Programmierer heißt das, dass man auch den Fall von Null Zeilen in den Pseudo-Tabellen berücksichtigen muss:
CREATE TRIGGER TR_USER_AR_UPD_CountTest ON Artikel
FOR UPDATE
AS
/*
** Dieser Trigger dient NUR zur Verdeutlichung der im
** Text beschriebenen Problematik.
** Dies ist ansonsten KEIN gültiger Trigger für die Verwendung
** mit der EULANDA®-Warenwirtschaft!
*/
IF UPDATE(Barcode)
SELECT COUNT(*) [Betroffene Zeilen mit Barcode-Änderung]
FROM inserted
ELSE SELECT COUNT(*) [Keine Barcode Änderungen] FROM inserted
GO
UPDATE Artikel SET Barcode = '4711' WHERE 1 = 2
GO
DROP TRIGGER TR_USER_AR_UPD_CountTest
Namenskonventionen
cn_UserId
RAISERROR
Erstellen von Benutzer-Indizes
Erstellen von Benutzer-Check-Constraints