euuser
Goto Top

SQL Server 2012 Update-Trigger

Hallo zusammen,

ich habe eine Frage zu einem Update-Trigger im SQL Server 2012:

Ich habe einen Trigger, der bei einem Update eines Datensatzes automatisch die Attribute modified und modifiedby füllen sollte:

USE [Database]
GO

CREATE TRIGGER [dbo].[Modified] ON [dbo].Tabelle
AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Tabelle 
SET dbo.Tabelle.modified = now, dbo.Tabelle.modifiedby = SUSER_SNAME()
FROM dbo.Tabelle
JOIN inserted
ON dbo.Tabelle.key = inserted.key
END

Leider bekomme ich immer die Fehlermeldung:
Meldung 156, Ebene 15, Status 1, Prozedur Modified, Zeile 11
Falsche Syntax in der Nähe des key-Schlüsselworts.

Ich komme einfach nicht dahinter, wo der Fehler liegt...

Es wäre schön, wenn jmd hier mir helfen könnte!

Vielen Dank schon einmal und schöne Grüße!
Felix

Content-ID: 230662

Url: https://administrator.de/contentid/230662

Ausgedruckt am: 25.11.2024 um 02:11 Uhr

Biber
Biber 21.02.2014 aktualisiert um 14:14:25 Uhr
Goto Top
Moin EUuser,

könnte ja ganz banal das fehlende Semikolon sein... face-wink

Aber:
  • Warum ein AFTER INSERT-Trigger (statt BEFORE INSERT) und drängender noch

  • warum keine Füllung der Felder durch einen DEFAULT-Wert?

Die Felder können doch durchaus NOT NULL deklariert werden, wenn sie ohnehin immer gefüllt werden.
Und auch SUSER_SNAME kann als DEFAULT-Einschränkung in ALTER TABLE oder CREATE TABLE verwendet werden.

  • Warum ein Join auf die Tabelle "inserted"???? Wogegen soll das denn helfen?

  • Was treibt dich, ohne Not bei deinen Tabellen/Feldern Namen wie "inserted", "modified" oder "key" zu verwenden.
Also reservierte Worte oder Worte mit hoher Kollisionsgefahr in jedem SQL-Dialekt - und absolut nicht eindeutig.
Hasardeur? Oder sonst zu wenig Nervenkitzel zu Hause?

Grüße
Biber
EUuser
EUuser 21.02.2014 aktualisiert um 15:53:45 Uhr
Goto Top
Zitat von @Biber:

Moin EUuser,

könnte ja ganz banal das fehlende Semikolon sein... face-wink

Aber:
  • Warum ein AFTER INSERT-Trigger (statt BEFORE INSERT) und drängender noch

  • warum keine Füllung der Felder durch einen DEFAULT-Wert?

Die Felder können doch durchaus NOT NULL deklariert werden, wenn sie ohnehin immer gefüllt werden.
Und auch SUSER_SNAME kann als DEFAULT-Einschränkung in ALTER TABLE oder CREATE TABLE verwendet werden.

  • Warum ein Join auf die Tabelle "inserted"???? Wogegen soll das denn helfen?

  • Was treibt dich, ohne Not bei deinen Tabellen/Feldern Namen wie "inserted", "modified" oder "key"
zu verwenden.
Also reservierte Worte oder Worte mit hoher Kollisionsgefahr in jedem SQL-Dialekt - und absolut nicht eindeutig.
Hasardeur? Oder sonst zu wenig Nervenkitzel zu Hause?

Grüße
Biber

Hi Biber,

ich hab das mal so gelernt
ich möchte ja nur am gerade geupdateten Datensatz die Attribute"modified" und "modifiedby" füllen.

Falls du einen Tipp für einen besseren Weg kennst, dann immer her damit. face-smile

VG
Felix


EDIT:
Okay... hab es mit default werten gelöst
EUuser
EUuser 21.02.2014 um 15:56:40 Uhr
Goto Top
Zitat von @Biber:

Moin EUuser,

könnte ja ganz banal das fehlende Semikolon sein... face-wink

Aber:
  • Warum ein AFTER INSERT-Trigger (statt BEFORE INSERT) und drängender noch

  • warum keine Füllung der Felder durch einen DEFAULT-Wert?

Die Felder können doch durchaus NOT NULL deklariert werden, wenn sie ohnehin immer gefüllt werden.
Und auch SUSER_SNAME kann als DEFAULT-Einschränkung in ALTER TABLE oder CREATE TABLE verwendet werden.

  • Warum ein Join auf die Tabelle "inserted"???? Wogegen soll das denn helfen?

  • Was treibt dich, ohne Not bei deinen Tabellen/Feldern Namen wie "inserted", "modified" oder "key"
zu verwenden.
Also reservierte Worte oder Worte mit hoher Kollisionsgefahr in jedem SQL-Dialekt - und absolut nicht eindeutig.
Hasardeur? Oder sonst zu wenig Nervenkitzel zu Hause?

Grüße
Biber


Okay, verstanden

Jetzt die große Frage: Wie mach ich das am besten, wenn ich einen Trigger für ganz neue Tupel, sprich ein created und createdby -Attribut füllen möchte?
Das darf ja nicht bei jedem Updatevorgang überschrieben werden


VG und Danke
Felix
Biber
Biber 21.02.2014 um 17:03:34 Uhr
Goto Top
Moin EUuser,

sorry, ich hatte auch überlesen, dass es um einen UPDATE-Trigger ging. Mein Fehler.

Also: je nach Anforderung der "Updateprotokollierung" sehe ich zwei Möglichkeiten:
a) es so das Ereignis "Satz neu angelegt von user am Datum" automatisch mit erfasst werden und das Datum des letzten Updates und der ändernde User
b) es soll eine komplette Historie im Hintergrund erzeugt werden mit alle jemals vorhandenden Datensatzzuständen, also auch dem Ereignis "Satz wurde gelöscht" sowie Löschdatum+löschender User

Fall a) geht ja innerhalb dieser einen Tabellen - mit
  • 2 Feldern für CreatedTS, CreatedBy (per Default gefüllt)
  • 2 Feldern für ModifiedTS, ModifiedBy (per BEFORE UPDATE-Trigger gefüllt, Felder nicht sichtbar für den User und nicht gesetzt per etwaigem Update-Statement)

Fall b) ist aufwendiger - der geht ja nur mit einer Clone-Tabelle (=alle Felder der Originaltabelle), und zusätzlich die Felder:
  • ValidFromTS und ValidToTS gehören für den Gültig-Von/Gültig-Bis-Zeitraum des aktiven Satzes
  • ein Feld für die UserID created/modified (modifiedBy)
  • ein Feld für die UserID (deletedBy)

Dann brauchst du allerdings auf der Originaltabelle 3 Trigger:
- einen After Insert-Trigger auf der Originaltabelle
-> legt eine Kopie des gerade angelegten Originalsatzes in der Hist-Tabelle an mit ValidFrom =now() und ValidTo = unendlich /31.12.9999 und der UserId ins Feld "modifiedBy"
- einen After Update-Trigger auf der Originaltabelle
-> ändert den Historiesatz, der "unendlich" gültig war auf "ValidToTS = now() minus 1 Sekunde und legt eine Kopie des gerade angelegten Originalsatzes in der Hist-Tabelle an mit ValidFrom =now() und ValidTo = unendlich /31.12.9999 und der UserId ins Feld "modifiedBy"

- einen After Delete-Trigger auf der Originaltabelle
-> ändert den Historiesatz, der "unendlich" gültig war auf "ValidToTS = now() minus 1 Sekunde und setzt das Feld deletedBy


Grüße
Biber
MadMax
MadMax 24.02.2014 um 13:20:37 Uhr
Goto Top
Hallo Felix,

mal abgesehen von den ganzen Sachen, die Biber Dir da noch versucht beizubringen, liegt Dein Problem an den Namen Deiner Spalten und könnte Dich also auch an anderer Stelle in Schwierigkeiten bringen. "key" ist ein Schlüsselwort in SQL Server und kann so nicht verwendet werden. Mal abgesehen davon, daß man solche Schlüsselworte als Spalten- oder sonstige Objektnamen meiden sollte, könnte man sie auch in eckige Klammern packen und dann trotzdem verwenden. [key] geht also, key geht nicht. Aber wie gesagt: besser ist, man vermeidet das gänzlich.

Gruß, Mad Max
EUuser
EUuser 27.02.2014 um 13:45:39 Uhr
Goto Top
Zitat von @Biber:

Moin EUuser,

sorry, ich hatte auch überlesen, dass es um einen UPDATE-Trigger ging. Mein Fehler.

Also: je nach Anforderung der "Updateprotokollierung" sehe ich zwei Möglichkeiten:
a) es so das Ereignis "Satz neu angelegt von user am Datum" automatisch mit erfasst werden und das Datum des letzten
Updates und der ändernde User
b) es soll eine komplette Historie im Hintergrund erzeugt werden mit alle jemals vorhandenden Datensatzzuständen, also auch
dem Ereignis "Satz wurde gelöscht" sowie Löschdatum+löschender User

Fall a) geht ja innerhalb dieser einen Tabellen - mit
  • 2 Feldern für CreatedTS, CreatedBy (per Default gefüllt)
  • 2 Feldern für ModifiedTS, ModifiedBy (per BEFORE UPDATE-Trigger gefüllt, Felder nicht sichtbar für den User und
nicht gesetzt per etwaigem Update-Statement)

Fall b) ist aufwendiger - der geht ja nur mit einer Clone-Tabelle (=alle Felder der Originaltabelle), und zusätzlich die
Felder:
  • ValidFromTS und ValidToTS gehören für den Gültig-Von/Gültig-Bis-Zeitraum des aktiven Satzes
  • ein Feld für die UserID created/modified (modifiedBy)
  • ein Feld für die UserID (deletedBy)

Dann brauchst du allerdings auf der Originaltabelle 3 Trigger:
- einen After Insert-Trigger auf der Originaltabelle
-> legt eine Kopie des gerade angelegten Originalsatzes in der Hist-Tabelle an mit ValidFrom =now() und ValidTo = unendlich
/31.12.9999 und der UserId ins Feld "modifiedBy"
- einen After Update-Trigger auf der Originaltabelle
-> ändert den Historiesatz, der "unendlich" gültig war auf "ValidToTS = now() minus 1 Sekunde und
legt eine Kopie des gerade angelegten Originalsatzes in der Hist-Tabelle an mit ValidFrom =now() und ValidTo = unendlich
/31.12.9999 und der UserId ins Feld "modifiedBy"

- einen After Delete-Trigger auf der Originaltabelle
-> ändert den Historiesatz, der "unendlich" gültig war auf "ValidToTS = now() minus 1 Sekunde und
setzt das Feld deletedBy


Grüße
Biber

Hi Biber,

genau Fall a möchte ich abbilden.
Wie bekomme ich es denn hin, dass ich nur in dem gerade geänderten Datensatz per Trigger die Attribute ModifiedTS und ModifiedBy füllen lasse.
Meine Trigger überschreiben dann alle Datensätze, was ja nicht ganz der Sinn der Sache ist... ;)
Ich nutze für ModifiedTS GetDate() und für ModifiedBy System_User.
EUuser
EUuser 27.02.2014 um 16:08:09 Uhr
Goto Top
So liebe Leute,
nach etwas rumprobieren fiel es mir wie Schuppen aus den Haaren:

USE [Database]
GO

CREATE TRIGGER [dbo].[Modified] ON [dbo].Tabelle
AFTER INSERT, UPDATE
AS 
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Tabelle 
SET dbo.Tabelle.ModifiedTS = GetDate(), dbo.Tabelle.ModifiedBy = SYSTEM_USER
FROM dbo.Tabelle
JOIN inserted
ON dbo.Tabelle.Primärschlüssel = inserted.Primärschlüssel
END

Danke für eure Hilfe und Denkanstöße!

VG
Felix