Benutzer mit den meisten Antworten
Trigger und Tabelle 'Inserted'

Frage
-
Hallo
Ich möchte eine History für eine meiner Tabellen machen. Nach jedem hinzufügen eines Datensatzes sollte er mir gewisse Daten in Meine History-Tabelle schreiben. Soweit ich verstanden habe wäre da ein Insert-Trigger eine gute Variante
Also habe ich mir folgendes gebastelt:
CREATE TRIGGER tgrWriteHistory ON dbo.tblakte AFTER INSERT AS INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) values (1, inserted.pAkte, 'frmAkte', 'MainSubject', 0, inserted.MainSubject, 109, 0 , 0, 0, GETDATE(), 'xyz', 'pc'), (1, inserted.pAkte, 'frmAkte', 'CreationPeriodFrom', 0, inserted.CreationPeriodFrom, 109, 0, 0, 0, GETDATE(), 'xyz', 'pc') GO
Mit meinen Grundkentnissen erwarte ich, dass 'Inserted' mir den Verweis auf den Datensatz gibt, der gerade angefügt wurde und ich somit die einzelnen Felder von dort auslesen kann.
Wenn ich aber den Trigger kreieren möchte kommt immer die Fehlermeldung mit #4104 'The multi-part identifier "inserted.pAkte" could not be bound', 'The multi-part identifier "inserted.MainSubject" could not be bound.' für alle inserted...-Felder.
Die Erklärungen zu dem Fehler bringen mich nicht weiter.
Was mache ich falsch?
Danke und Gruss Thomas
Antworten
-
Hallo Thomas,
Du brauchst zwei Inserts oder ein UNION ALL für die Selects.
alter TRIGGER tgrWriteHistory ON dbo.tblakte AFTER INSERT AS INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select 1, pAkte, 'frmAkte', 'MainSubject', 0, MainSubject, 109, 0 , 0, 0, GETDATE(), 'xyz', 'pc' from inserted; INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select 1, pAkte, 'frmAkte', 'CreationPeriodFrom', 0, CreationPeriodFrom, 109, 0, 0, 0, GETDATE(), 'xyz', 'pc' from inserted; GO
Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu
- Als Antwort markiert Alphawolfi Freitag, 1. November 2019 10:58
Alle Antworten
-
Leider falsch gedacht.
Da der Trigger je Statement und nicht je Zeile aufgerufen wird enthält die Tabelle Inserted alle hinzugefügten Zeile in Kopie.
Du muss also per Cursor mittels "Select * from Inserted" die Daten kopieren.
Dies geht natürlich auch in einem SQL:CREATE TRIGGER tgrWriteHistory ON dbo.tblakte AFTER INSERT AS INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select .... from Inserted GO
Die "...." ersetzt du natürlich durch die benötigten Felder.
Der Afterinsert-Trigger ist vor allem bei Bulkinserts schädlich, da die Daten komplett noch mal in die TempDB für den Trigger geschrieben werden.
Sollte man dabei auch noch auf die Idee kommen, die Daten verändern zu wollen, wird auch noch das Satzversioning scharf gemacht, was zusätzlich die TempDB belastet.Alternativ kann man dies nur per Instead-of-Trigger lösen.
-
Für den Trigger ist das unerheblich ob nur 1 Zeile oder n Zeilen eingefügt wurden.
Das Prinzip ist immer dasselbe. Die Tabelle "Inserted" enthält dann halt nur 1 Zeile.Mehrere Zeilen kann man durch mehrere Values erreichen:
insert into mytable [(F1, ....)]
Values
(.....)
(.....)
;
insert into mytable [(F1, ...)]
Select F1, ... from othertable where ...Der Trigger wird aber nur 1 Mal aufgerufen auch wenn 2 oder mehr Zeilen eingefügt wurden.
- Bearbeitet Der Suchende Donnerstag, 31. Oktober 2019 09:55
-
Mit dem Value schlüsselwort ist mir klar dass ich mehrere Wert einfügen kann.
Aber wie Du mir eben erklärt hast muss ich für mein Vorhaben eine Select-Anweisung angeben.
Mein Trigger sieht momentan so aus:
alter TRIGGER tgrWriteHistory ON dbo.tblakte AFTER INSERT AS INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) (select 1, pAkte, 'frmAkte', 'MainSubject', 0, MainSubject, 109, 0 , 0, 0, GETDATE(), 'xyz', 'pc' from inserted) (select 1, pAkte, 'frmAkte', 'CreationPeriodFrom', 0, CreationPeriodFrom, 109, 0, 0, 0, GETDATE(), 'xyz', 'pc' from inserted) GO
Jetzt konnt ich ihn immerhin speichern, aber er führt im Test nur die erste Anweisung (die mit dem MainSubject) aus, die zweite ignoriert er
Danke und Gruss Thomas
-
Hallo Thomas,
Du brauchst zwei Inserts oder ein UNION ALL für die Selects.
alter TRIGGER tgrWriteHistory ON dbo.tblakte AFTER INSERT AS INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select 1, pAkte, 'frmAkte', 'MainSubject', 0, MainSubject, 109, 0 , 0, 0, GETDATE(), 'xyz', 'pc' from inserted; INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select 1, pAkte, 'frmAkte', 'CreationPeriodFrom', 0, CreationPeriodFrom, 109, 0, 0, 0, GETDATE(), 'xyz', 'pc' from inserted; GO
Einen schönen Tag noch, Christoph - http://www.insidesql.org/blogs/cmu
- Als Antwort markiert Alphawolfi Freitag, 1. November 2019 10:58
-
Ein Select liefert ein Resultset.
In Klammern wäre das ein scalarer Subselect, der nur 1 Zeile und 1 Wert liefern darf.
Daher wähle am Besten den Union all:INSERT INTO dbo.tblHistory (HistoryChange, PrimaryKeyNr, NameSubForm, FieldNameShow, OldValue, NewValue, FieldControlType, FieldControlColumn, OldFieldBoundColumn, NewFieldBoundColumn, InsertDateTime, NameUser, NameWorkstation) select 1, pAkte, 'frmAkte', 'MainSubject', 0, MainSubject, 109, 0 , 0, 0, GETDATE(), 'xyz', 'pc' from inserted
union allselect 1, pAkte, 'frmAkte', 'CreationPeriodFrom', 0, CreationPeriodFrom, 109, 0, 0, 0, GETDATE(), 'xyz', 'pc' from inserted
- Bearbeitet Der Suchende Donnerstag, 31. Oktober 2019 18:55