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!

Dienstag, 8. Mai 2007

Konvertieren von Zeichenfolgen in Format mit großen Anfangsbuchstaben

Manchmal kommt man in die Lage Zeichenfolgen, die ausschließlich klein geschrieben wurden (Gruß an alle E-Mail-Kleinschreiber ;-)), so zu konvertieren, dass die Anfangsbuchstaben der Wörter mit einem Großbuchstaben beginnen.
Das kann ganz einfach mit der Methode ToTitleCase() der Klasse TextInfo bewerkstelligt werden.
Um die Klasse TextInfo verwenden zu können, benötigt man ein Objekt der Klasse CultureInfo. Dazu kann fast immer die voreingestellte Culture verwendet werden, die man über den aktuellen Thread abrufen kann.


string beispielString = "mein blog";
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
TextInfo ti = ci.TextInfo;
beispielString = ti.ToTitleCase(beispielString);


Das Beispiel konvertiert den String "beispielString" in das Ergebnis "Mein Blog".