Mittwoch, 16. Mai 2007

UPDATE Trigger - schon mal reingefallen?

Vielleicht ist der ein oder andere schon mal darauf reingefallen:

Nach einem Update auf einen Datensatz einer Tabelle soll ein Update-Trigger, z.B. den PrimaryKey des aktualisierten Datensatzes verwendet um weitere Prozesse anzustoßen.
So sieht der Code dazu z.B. zunächst mal so aus:



CREATE TRIGGER [TRIGGER NAME] ON [dbo].[myTableName]
FOR INSERT, UPDATE, DELETE
AS
[dein Code ...]


Man kann nun im Codebereich eigene Variablen definieren und Werte des aktuell betroffenen Datensatzes weiterverarbeiten

Beispiel für einen hinzugefügten Datensatz


CREATE TRIGGER [TRIGGER NAME_Insert] ON [dbo].[myTableName]
FOR INSERT
AS
DECLARE @myInsertId int
SELECT @myInsertId=myTableId FROM INSERTED
[weitere Verarbeitung ...]

Damit kann deraktuell eingefügte Wert der Spalte myTableId weiter verarbeitet werden.

Das funktioniert natürlich auch beim Aktualisieren eines Datensatzes mit UPDATE.
Wer nun aber versucht mit folgendem Code zum Ziel zu kommen, wird bitter enttäuscht werden:



CREATE TRIGGER [TRIGGER_NAME_Insert] ON [dbo].[myTableName]
FOR UPDATE
AS
DECLARE @myInsertId int
SELECT @myInsertId=myTableId FROM UPDATED
[weitere Verarbeitung ...]


Der Teufel liegt hier im Detail. Die Codezeile

SELECT @myInsertId=myTableId FROM UPDATED

wird leider nicht den gewünschten Effekt haben und den Wert des aktualisierten Datensatzes für die Spalte myTableId liefern. Das liegt daran, dass der SQLServer ein Update auf einen Datensatz intern mit einem Delete und Insert abhandelt.
Der folgende Code sollte somit das Problem lösen:



CREATE TRIGGER [TRIGGER_NAME_Update] ON [dbo].[myTableName]
FOR UPDATE
AS
DECLARE @myInsertId int
SELECT @myInsertId=myTableId FROM INSERTED
[weitere Verarbeitung ...]


Damit kann man auch schön den alten und den neuen Wert einer Aktualisierung verarbeiten:


CREATE TRIGGER [TRIGGER_NAME_Update] ON [dbo].[myTableName]
FOR UPDATE
AS
DECLARE @myEmail_old varchar(150)
DECLARE @myEmail_new varchar(150)

SELECT @myEmail_old=myEmail FROM DELETED
SELECT @myEmail_new=myEmail FROM INSERTED

[weitere Verarbeitung ...]


Vielleicht hilfts ja dem ein oder anderen ;-)

Da wär noch was:
Thomas Glörfeld hat mich in seinem Blog darauf hingwiesen, dass man bei der Verwendung immer darauf achten sollte, dass bei einem Update meist möglichst viele betroffene Datensätze mit einem Statement zu aktualisieren, das o.a. Beispiel aber davon ausgeht dass eben nur ein Datensatz oder nur wenige davon betroffen sind - also für einen umfangreichen Update ungeeignet ist. Leider ist dort mein Beispiel etwas aus dem Zusammenhang gerissen.
Als "altgedienter" ;-) Programmierer verwende ich natürlich ebenfalls ein SQL-Statement zur Aktualisierung mehrer Datensätze (sofern möglich) und nicht einzelne SQL-Befehle die über eine Schleife o.ä. ausgeführt werden. Mein Beispiel sollte nur die Problematik mit dem Update-Trigger veranschaulichen.
Aber natürlich schließe ich mich Thomas' Empfehlung "Im Trigger selber bitte immer die Verarbeitung von mehreren Datensätzen vorsehen." gerne an!

1 Kommentar:

Unknown hat gesagt…

Ja, ich bin auch reingefallen.
Genau danach habe ich gesucht.
Vielen Dank fürs Posten.

Thomas Hausdorf