So erhalten Sie die letzte Identitätszeile Wird bei Verwendung anstelle von Trigger eingefügt

8

Wenn ich in Tabellen einfügen anstelle von Trigger verwenden, @@Identity, IDENT_CURRENT('Table')und SCOPE_IDENTITY()null zurück. Wie kann ich die letzte Identität der eingefügten Zeile erhalten?

mehdi lotfi
quelle
insertedBeim INSTEAD OFAuslösen eines Triggers wird jedoch keine Zeile eingefügt .
Ypercubeᵀᴹ
Überprüfen Sie diese SO-Frage: Es kann helfen. stackoverflow.com/q/908257/27535
gbn
Sie müssen Select Id, .. aus Inserted auswählen, hier Scope_Identity, @@ Identity funktioniert nicht

Antworten:

8

Mit einem INSTEAD_OF-Trigger bedeutet dies, dass noch keine Einfügung erfolgt ist. Sie können die Identität nicht kennen, da sie noch nicht generiert wurde. Das Löschen des Werts aus Metadaten ist möglich ( DBCC CHECKIDENT), aber wenn Sie sich darauf verlassen, funktioniert dies bei gleichzeitiger Verwendung nicht richtig und erfordert außerdem erhöhte Berechtigungen.

INSTEAD_OF-Trigger sind äußerst selten erforderlich und riechen ernsthaft nach Code. Bist du sicher, dass du es brauchst? Können Sie die Arbeit nicht mit einem regulären AFTER-Trigger erledigen?

Remus Rusanu
quelle
Ich möchte die Datenintegrität der eingefügten Zeile steuern. bevor Sie sie speichern. Wenn die Daten nicht gut sind, erhalte ich eine fehlerproportionale Meldung.
Mehdi Lotfi
2
Sie beschreiben einen Fremdschlüssel. Es sollte in der Verantwortung der Anwendung liegen, in die untergeordnete Tabelle einzufügen, nicht in einen Trigger. Es ist ein schlechtes Design, es von einem Trigger aus zu machen, und es kann sowieso von einem normalen AFTER-Trigger aus gemacht werden. Ein After-Trigger kann Fehler auslösen und ein Rollback verursachen. Dies ist die bessere Option als ein Trigger anstelle eines Triggers.
Remus Rusanu
1
Was für eine absurde Vorstellung - "statt Auslöser riecht es ernsthaft nach Code"? Sie sind sehr nützlich im Vergleich zu einem After-Trigger. Wenn Ihre Geschäftsregeln verletzt werden, haben Sie die Arbeit zweimal ausgeführt. Sie haben die Zeilen eingefügt und sie dann zurückgesetzt. Ein anstelle eines Auslösers kann verhindern, dass Arbeiten ausgeführt werden, wenn Ihre Geschäftsregeln nicht mit normalem DRI oder anderen Einschränkungen durchgesetzt werden können.
Aaron Bertrand
1
Während "anstelle von Triggern ein schwerwiegender Codegeruch" keine strenge Regel ist, basiert sie auf tatsächlich möglichen Problemen, die in einem vollständigen System verursacht werden können. Im Allgemeinen sollten im Regel niemals Verstöße gegen Geschäftsregeln im System auftreten, geschweige denn die Datenbankebene erreichen. In diesem Fall ist eine Regelüberprüfung im Trigger nur als letzter Abwehrmechanismus geeignet, wenn das System eine Lücke aufweist.
Alireza
4
Deklarative Integrität ist immer besser als ein Auslöser. Ein After-Trigger ist immer besser als ein anstelle eines Triggers. Anstatt dass Trigger in vielen Situationen ein "funky" Verhalten aufweisen, sind sie für den Zugriff auf Pfadoptimierungen in DML undurchsichtig und sorgen dafür, dass sich Isolationsstufen unregelmäßig verhalten. Anstelle von Auslösern schreien "Ich hätte stattdessen eine gespeicherte Zugriffsprozedur sein sollen". Und ich kaufe das Argument "Arbeit zweimal erledigen" überhaupt nicht. Die Optimierung des Ausnahmepfads sollte das Design nicht beeinflussen, insbesondere auf Kosten der Verlangsamung des häufigen Pfads.
Remus Rusanu
11

Anstelle von Trigger können Sie definitiv den eingefügten Wert erhalten ... aber erst, nachdem Sie das Einfügen durchgeführt haben.

USE tempdb;
GO

CREATE TABLE dbo.SmellThis
(
  id INT IDENTITY(1,1),
  name VARCHAR(32)
);
GO

CREATE TRIGGER dbo.SmellThis_First
ON dbo.SmellThis
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @ids TABLE(id INT);

    IF NOT EXISTS 
    (
      SELECT 1 FROM sys.objects AS o
        INNER JOIN inserted AS i
        ON o.name = i.name
    )
    INSERT dbo.SmellThis(name)  
      OUTPUT inserted.id INTO @ids
      SELECT name 
      FROM inserted;

    SELECT id FROM @ids;
END
GO

INSERT dbo.SmellThis(name) SELECT 'Remus';
GO

Ergebnisse:

id
----
1

Jetzt aufräumen:

DROP TABLE dbo.SmellThis;

Abgesehen davon sollten Sie niemals @@IDENTITYoder niemals etwas verwenden IDENT_CURRENT(). Und SCOPE_IDENTITYsollte für Situationen reserviert werden, in denen Sie wissen, dass immer nur eine Zeile eingefügt werden kann. Ein häufiges Missverständnis bei Triggern ist, dass sie wie auf anderen Plattformen pro Zeile ausgelöst werden, in SQL Server jedoch pro Operation - also eine mehrzeilige Einfügung mit VALUES(),(),()oder INSERT...SELECT- welche SCOPE_IDENTITYwürden Sie für Ihre Variable festlegen?

Aaron Bertrand
quelle
So speichere ich das Ergebnis eines eingefügten Datensatzes in einer Variablentabelle zur späteren Verwendung.
Mehdi Lotfi
@mehdi kannst du "später" definieren? Und können Sie der oben bereits deklarierten Tabellenvariablen keine Spalten hinzufügen?
Aaron Bertrand
2
Ich liebe deine Tischnamen.
Dan Esparza
-1

Hauptproblem: Trigger- und Entity-Framework arbeiten beide in unterschiedlichem Umfang. Das Problem ist, dass wenn Sie im Trigger einen neuen PK-Wert generieren, dieser einen anderen Bereich hat. Somit gibt dieser Befehl null Zeilen zurück und EF löst eine Ausnahme aus.

Die Lösung besteht darin, die folgende SELECT-Anweisung am Ende Ihres Triggers hinzuzufügen:

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

Anstelle von * können Sie alle Spaltennamen einschließlich angeben

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
Ashish Mishra
quelle