Was ist der Unterschied zwischen Scope_Identity (), Identity (), @@ Identity und Ident_Current ()?


190

Ich weiß Scope_Identity(), Identity(), @@Identity, und Ident_Current()alle den Wert der Identitätsspalte, aber ich würde gerne den Unterschied kennen.

Ein Teil der Kontroverse, die ich habe, ist, was sie unter Umfang verstehen, wie er auf diese Funktionen oben angewendet wird.

Ich würde auch ein einfaches Beispiel für verschiedene Szenarien ihrer Verwendung lieben?


2
Vergessen Sie nicht den Fehler bei der parallelen Ausführung, der in SQL Server für SCOPE_IDENTITY und @@ IDENTITY auftritt: support.microsoft.com/default.aspx?scid=kb;en-US;2019779
David d C e Freitas

@DaviddCeFreitas - Ich bin gespannt auf den Fehler, aber der Link scheint defekt zu sein (oder zumindest einen ASP-Fehler auszulösen).
rory.ap

2
Eigentlich habe ich es gefunden: support.microsoft.com/en-us/kb/2019779
rory.ap

Fix wurde veröffentlicht, wie in diesem alten KB-Artikel erwähnt
George Birbilis

Antworten:


391
  • Die @@identityFunktion gibt die zuletzt in derselben Sitzung erstellte Identität zurück.
  • Die scope_identity()Funktion gibt die zuletzt in derselben Sitzung und demselben Bereich erstellte Identität zurück.
  • Das ident_current(name)gibt die letzte Identität zurück, die für eine bestimmte Tabelle oder Ansicht in einer Sitzung erstellt wurde.
  • Die identity()Funktion wird nicht zum Abrufen einer Identität verwendet, sondern zum Erstellen einer Identität in einer select...intoAbfrage.

Die Sitzung ist die Datenbankverbindung. Der Bereich ist die aktuelle Abfrage oder die aktuell gespeicherte Prozedur.

Eine Situation, in der sich die scope_identity()und die @@identityFunktionen unterscheiden, ist, wenn Sie einen Auslöser auf dem Tisch haben. Wenn Sie eine Abfrage haben, die einen Datensatz einfügt, wodurch der Trigger irgendwo einen anderen Datensatz einfügt, gibt die scope_identity()Funktion die von der Abfrage erstellte Identität zurück, während die @@identityFunktion die vom Trigger erstellte Identität zurückgibt.

Normalerweise würden Sie die scope_identity()Funktion verwenden.


14
Ich habe dies als Antwort gewählt, da der Absatz "Eine Situation, in der scope_identity () und @@ identity ..." angezeigt wird. Es hat die Dinge mehr geklärt.
Tebo

1
Wie David Freitas oben erwähnt hat, gibt es einen Fehler bei der Implementierung von scope_identity. Ich empfehle daher, eine alternative Methode zu verwenden, die OUTPUT-Klausel. Siehe meine Antwort unten.
Sebastian Meine

@Guffa - "Die Sitzung ist die Datenbankverbindung". Wird die Sitzung verbindungsübergreifend aufrechterhalten, wenn Sie das Verbindungspooling verwenden?
Dave Black

1
Dies ist eine Vorbildantwort. Insbesondere die Arbeit mit SQL und SQL Server kann seltsam sein, und dies erklärt die Dinge auf sehr klare Weise für Laien, ist aber dennoch ziemlich informativ. Es hört sich nicht so an, als würde etwas zwischen zwei Datenbankspezialisten kommuniziert, was viele andere SE-Antworten tun.
Panzercrisis

@ DaveBlack von dem, was ich gelesen habe: Nein, Sitzung wird nicht im Pool verwaltet, Sitzung ist eindeutig für Ihre Skriptausführung nach connect (). Beim Pooling ... PHP für SQL Server verwendet das ODBC-Verbindungspooling. Wenn eine Verbindung aus dem Pool verwendet wird, wird der Verbindungsstatus zurückgesetzt. Durch Schließen der Verbindung wird die Verbindung zum Pool zurückgegeben. (Hinweis: siehe Anmerkungen zu Linux / Mac) docs.microsoft.com/en-us/sql/connect/php/…
GDmac

42

Gute Frage.

  • @@IDENTITY: Gibt den letzten Identitätswert zurück, der auf Ihrer SQL-Verbindung (SPID) generiert wurde. Meistens ist es das, was Sie wollen, aber manchmal ist es nicht so (wie wenn ein Trigger als Reaktion auf eine ausgelöst wird INSERTund der Trigger eine andere INSERTAnweisung ausführt ).

  • SCOPE_IDENTITY(): Gibt den letzten im aktuellen Bereich generierten Identitätswert zurück (dh gespeicherte Prozedur, Trigger, Funktion usw.).

  • IDENT_CURRENT(): Gibt den letzten Identitätswert für eine bestimmte Tabelle zurück. Verwenden Sie diese Option nicht, um den Identitätswert von a abzurufen. Dies INSERTunterliegt den Race-Bedingungen (dh mehreren Verbindungen, die Zeilen in dieselbe Tabelle einfügen).

  • IDENTITY(): Wird verwendet, wenn eine Spalte in einer Tabelle als Identitätsspalte deklariert wird.

Weitere Informationen finden Sie unter: http://msdn.microsoft.com/en-us/library/ms187342.aspx .

Zusammenfassend: Wenn Sie Zeilen einfügen und den Wert der Identitätsspalte für die gerade eingefügte Zeile wissen möchten, verwenden Sie immer SCOPE_IDENTITY().


16

Wenn Sie den Unterschied zwischen Umfang und Sitzung verstehen, ist es sehr einfach, diese Methoden zu verstehen.

Ein sehr schöner Blog-Beitrag von Adam Anderson beschreibt diesen Unterschied:

Sitzung bedeutet die aktuelle Verbindung, die den Befehl ausführt.

Bereich bedeutet den unmittelbaren Kontext eines Befehls. Jeder Aufruf einer gespeicherten Prozedur wird in einem eigenen Bereich ausgeführt, und verschachtelte Aufrufe werden in einem verschachtelten Bereich innerhalb des Bereichs der aufrufenden Prozedur ausgeführt. Ebenso wird ein SQL-Befehl, der von einer Anwendung oder einem SSMS ausgeführt wird, in seinem eigenen Bereich ausgeführt. Wenn dieser Befehl Trigger auslöst, wird jeder Trigger in seinem eigenen verschachtelten Bereich ausgeführt.

Somit sind die Unterschiede zwischen den drei Identitätsabrufmethoden wie folgt:

@@identityGibt den letzten in dieser Sitzung generierten Identitätswert zurück, jedoch einen beliebigen Bereich.

scope_identity()Gibt den letzten in dieser Sitzung generierten Identitätswert und diesen Bereich zurück.

ident_current()Gibt den letzten Identitätswert zurück, der für eine bestimmte Tabelle in einer Sitzung und einem Bereich generiert wurde .


11

Bereich bedeutet den Codekontext, der die INSERTAnweisung ausführt SCOPE_IDENTITY(), im Gegensatz zum globalen Bereich von @@IDENTITY.

CREATE TABLE Foo(
  ID INT IDENTITY(1,1),
  Dummy VARCHAR(100)
)

CREATE TABLE FooLog(
  ID INT IDENTITY(2,2),
  LogText VARCHAR(100)
)
go
CREATE TRIGGER InsertFoo ON Foo AFTER INSERT AS
BEGIN
  INSERT INTO FooLog (LogText) VALUES ('inserted Foo')
  INSERT INTO FooLog (LogText) SELECT Dummy FROM inserted
END

INSERT INTO Foo (Dummy) VALUES ('x')
SELECT SCOPE_IDENTITY(), @@IDENTITY 

Gibt unterschiedliche Ergebnisse.


9

Wegen des von @David Freitas erwähnten Fehlers und wegen der Inkompatibilität mit der neuen Sequence-Funktion, die 2012 eingeführt wurde, würde ich empfehlen, sich von allen drei fernzuhalten. Stattdessen können Sie die OUTPUT-Klausel verwenden, um den eingefügten Identitätswert abzurufen. Der andere Vorteil ist, dass OUTPUT auch funktioniert, wenn Sie mehr als eine Zeile eingefügt haben.

Details und Beispiele finden Sie hier: Identitätskrise


Ich denke, diese Antwort verdient mehr Aufmerksamkeit.
Cheeze

Leider funktioniert INSERT ... OUTPUT Inserted.xx nicht mit INSERT-Triggern (dasselbe gilt für UPDATE ... OUTPUT Updated.xx- und UPDATE-Trigger). Sie schlagen vor, INSERT ... OUTPUT INTO zu verwenden, aber es ist zu ausführlich und die Verwendung dieses von Clients (anstelle von gespeicherten Prozessen) ist problematisch. INSERT ... OUTPUT Inserted.xx ist schön, wenn es mit clientseitigen Aufrufen verwendet wird (zum Einfügen benötigen Sie lediglich einen ExecuteScalar und sagen Sie, dass Sie die automatisch generierte ID für die neue Zeile zurückerhalten möchten), wenn Sie die Trigger nicht benötigen.
George Birbilis

6

Um das Problem mit zu klären @@Identity :

Wenn Sie beispielsweise eine Tabelle einfügen und diese Tabelle Trigger für Einfügungen enthält, @@Identitywird die ID von der Einfügung im Trigger (a log_idoder so) zurückgegeben, während scope_identity()die ID von der Einfügung in der Originaltabelle zurückgegeben wird.

Wenn Sie also keine Trigger haben scope_identity()und @@identitydenselben Wert zurückgeben. Wenn Sie Auslöser haben, müssen Sie sich überlegen, welchen Wert Sie möchten.


4

Scope Identity: Identität des letzten Datensatzes, der innerhalb der ausgeführten gespeicherten Prozedur hinzugefügt wurde.

@@Identity: Identität des zuletzt im Abfragebatch hinzugefügten Datensatzes oder als Ergebnis der Abfrage, z. B. einer Prozedur, die eine Einfügung ausführt, löst der Trigger aus, der dann einen Datensatz einfügt, und gibt die Identität des eingefügten Datensatzes vom Trigger zurück.

IdentCurrent: Die letzte der Tabelle zugewiesene Identität.


3

Hier ist eine weitere gute Erklärung aus dem Buch :

Angenommen, Sie haben eine gespeicherte Prozedur P1 mit drei Anweisungen für den Unterschied zwischen SCOPE_IDENTITY und @@ IDENTITY:
- Ein INSERT, das einen neuen Identitätswert generiert.
- Ein Aufruf einer gespeicherten Prozedur P2, die auch eine INSERT-Anweisung hat, die eine neue generiert Identitätswert
- Eine Anweisung, die die Funktionen SCOPE_IDENTITY und @@ IDENTITY abfragt. Die Funktion SCOPE_IDENTITY gibt den von P1 generierten Wert zurück (gleiche Sitzung und gleicher Bereich). Die Funktion @@ IDENTITY gibt den von P2 generierten Wert zurück (dieselbe Sitzung unabhängig vom Umfang).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.