SQL: Wie erhalte ich die ID von Werten, die ich gerade eingefügt habe?


76

Ich habe einige Werte in eine Tabelle eingefügt. Es gibt eine Spalte, deren Wert automatisch generiert wird. In der nächsten Anweisung meines Codes möchte ich diesen Wert abrufen.

Kannst du mir sagen, wie ich es richtig mache?


6
Es ist hilfreich, wenn Sie einige Details dazu angeben, welche Datenbank Sie verwenden, da die Techniken variieren.
Auspuff

Antworten:


57

@@IDENTITY ist nicht bereichssicher und bringt Ihnen die ID aus einer anderen Tabelle zurück, wenn Sie einen Insert-Trigger für die ursprüngliche Tabelle haben. Verwenden Sie immer SCOPE_IDENTITY()


2
Es gibt bekannte Fehler mit SCOPE_IDENTITY () in SQL Server 2005, nicht sicher über 2008, die OUTPUT-Klausel kann bei Bedarf eine Reihe von IDs zurückgeben
KM.

1
Bekannter Fehler mit SCOPE_IDENTITY (), der die falschen Werte zurückgibt: blog.sqlauthority.com/2009/03/24/… Die Problemumgehung besteht darin, das INSERT nicht in einem parallelen Plan mit mehreren Prozessoren auszuführen oder die OUTPUT-Klausel
KM zu verwenden.

4
Die URL wird im Kommentar von @KM abgeschnitten. Hoffentlich funktioniert dieser Link: SCOPE_IDENTITY Fehler mit parallelem Plan und Lösung für mehrere Prozessoren
James Skemp

29

So mache ich meine Speicherprozeduren für MSSQL mit einer automatisch generierten ID.

CREATE PROCEDURE [dbo].[InsertProducts]
    @id             INT             = NULL OUT,
    @name           VARCHAR(150)    = NULL,
    @desc           VARCHAR(250)    = NULL

AS

    INSERT INTO dbo.Products
       (Name,
        Description)
    VALUES
       (@name,
        @desc)

    SET @id = SCOPE_IDENTITY();

14

Wenn Sie PHP und MySQL verwenden, können Sie die Funktion mysql_insert_id () verwenden, die Ihnen die ID des gerade eingegebenen Elements mitteilt.
Aber ohne deine Sprache und dein DBMS fotografiere ich hier nur im Dunkeln.


14

Dies funktioniert sehr gut in SQL 2005:

DECLARE @inserted_ids TABLE ([id] INT);

INSERT INTO [dbo].[some_table] ([col1],[col2],[col3],[col4],[col5],[col6])
OUTPUT INSERTED.[id] INTO @inserted_ids
VALUES (@col1,@col2,@col3,@col4,@col5,@col6)

Es hat den Vorteil, dass alle IDs zurückgegeben werden, wenn Ihre INSERT-Anweisung mehrere Zeilen einfügt.


11

Wieder keine sprachunabhängige Antwort, aber in Java geht es so:

Connection conn = Database.getCurrent().getConnection();  
PreparedStatement ps =  conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
try {  
    ps.executeUpdate();  
    ResultSet rs = ps.getGeneratedKeys();  
    rs.next();  
    long primaryKey = rs.getLong(1);  
} finally {  
    ps.close();  
}  

Schön, ich habe gerade nach diesem gesucht
raupach

8

Wenn Sie mit Oracle arbeiten:

In Tabelle einfügen (Felder ....) Werte (Werte ...) RÜCKGABE (Liste der Felder ...) INTO (Variablen ...)

Beispiel:

INSERT IN PERSON (NAME) VALUES ('JACK') RETURNING ID_PERSON IN vIdPerson

oder wenn Sie von ... Java mit einem CallableStatement anrufen (sry, es ist mein Feld)

INSERT IN PERSON (NAME) VALUES ('JACK') RETURNING ID_PERSON IN?

und Deklarieren eines Autput-Parameters für die Anweisung


6

Es gibt keine Standardmethode (genauso wie es keine Standardmethode zum Erstellen von IDs mit automatischer Inkrementierung gibt). Hier sind zwei Möglichkeiten, dies in PostgreSQL zu tun. Angenommen, dies ist Ihr Tisch:

CREATE TABLE mytable (
  id SERIAL PRIMARY KEY,
  lastname VARCHAR NOT NULL,
  firstname VARCHAR
);

Sie können dies in zwei Anweisungen tun, solange es sich um aufeinanderfolgende Anweisungen in derselben Verbindung handelt (dies ist in PHP mit Verbindungspooling sicher, da PHP die Verbindung zum Pool erst zurückgibt, wenn Ihr Skript fertig ist):

INSERT INTO mytable (lastname, firstname) VALUES ('Washington', 'George');
SELECT lastval();

lastval () gibt Ihnen den letzten automatisch generierten Sequenzwert an, der in der aktuellen Verbindung verwendet wird.

Die andere Möglichkeit besteht darin, die RETURNING- Klausel von PostgreSQL für die INSERT- Anweisung zu verwenden:

INSERT INTO mytable (lastname) VALUES ('Cher') RETURNING id;

Dieses Formular gibt eine Ergebnismenge wie eine SELECT- Anweisung zurück und ist auch praktisch, um jede Art von berechnetem Standardwert zurückzugeben.


Diese zurückgebende ID gibt im Resultset-Objekt das richtige Recht für Java?
Ankur Loriya

4

Ein wichtiger Hinweis ist, dass die Verwendung von SQL-Abfragen von Anbietern zum Abrufen der zuletzt eingefügten ID sicher ist, ohne dass gleichzeitige Verbindungen befürchtet werden müssen.

Ich dachte immer, Sie müssten eine Transaktion erstellen, um eine Zeile einzufügen, und dann die zuletzt eingefügte ID AUSWÄHLEN, um zu vermeiden, dass eine von einem anderen Client eingefügte ID abgerufen wird.

Diese herstellerspezifischen Abfragen rufen jedoch immer die zuletzt eingefügte ID für die aktuelle Verbindung zur Datenbank ab . Dies bedeutet, dass die zuletzt eingefügte ID nicht von anderen Client-Einfügungen beeinflusst werden kann, solange diese ihre eigene Datenbankverbindung verwenden.


4

Für SQL 2005:

Angenommen, die folgende Tabellendefinition:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [somevalue] [nchar](10) NULL,
) 

Sie können Folgendes verwenden:

INSERT INTO Test(somevalue)
OUTPUT INSERTED.ID
VALUES('asdfasdf')

Dies gibt den Wert der ID-Spalte zurück.


Dies funktioniert in den neueren SQL Server-Versionen immer noch hervorragend.
Dub Stylee

4

Auf der Website habe ich Folgendes herausgefunden:

SQL SERVER - @@ IDENTITY vs SCOPE_IDENTITY () vs IDENT_CURRENT - Abrufen der zuletzt eingefügten Identität des Datensatzes 25. März 2007 von pinaldave

SELECT @@ IDENTITY Gibt den letzten IDENTITY-Wert zurück, der für eine Verbindung erzeugt wurde, unabhängig von der Tabelle, die den Wert erzeugt hat, und unabhängig vom Umfang der Anweisung, die den Wert erzeugt hat. @@ IDENTITY gibt den zuletzt in Ihrer aktuellen Sitzung in eine Tabelle eingegebenen Identitätswert zurück. Während @@ IDENTITY auf die aktuelle Sitzung beschränkt ist, ist es nicht auf den aktuellen Bereich beschränkt. Wenn Sie einen Auslöser für eine Tabelle haben, der bewirkt, dass eine Identität in einer anderen Tabelle erstellt wird, erhalten Sie die zuletzt erstellte Identität, auch wenn es der Auslöser war, der sie erstellt hat.

SELECT SCOPE_IDENTITY () Gibt den letzten IDENTITY-Wert zurück, der für eine Verbindung und eine Anweisung im selben Bereich erzeugt wurde, unabhängig von der Tabelle, die den Wert erzeugt hat. SCOPE_IDENTITY () gibt wie @@ IDENTITY den zuletzt in der aktuellen Sitzung erstellten Identitätswert zurück, beschränkt ihn jedoch auch auf Ihren aktuellen Bereich. Mit anderen Worten, es wird der letzte Identitätswert zurückgegeben, den Sie explizit erstellt haben, und nicht jede Identität, die durch einen Trigger oder eine benutzerdefinierte Funktion erstellt wurde.

SELECT IDENT_CURRENT ('Tabellenname') Gibt den zuletzt in einer Tabelle erzeugten IDENTITY-Wert zurück, unabhängig von der Verbindung, die den Wert erstellt hat, und unabhängig vom Umfang der Anweisung, die den Wert erzeugt hat. IDENT_CURRENT ist nicht durch Umfang und Sitzung beschränkt. Es ist auf eine bestimmte Tabelle beschränkt. IDENT_CURRENT gibt den Identitätswert zurück, der für eine bestimmte Tabelle in einer Sitzung und einem Bereich generiert wurde.


Vielen Dank für die Erklärung!
Doug

2

Denken Sie daran, dass @@ IDENTITY die zuletzt erstellte Identität für Ihre aktuelle Verbindung zurückgibt, nicht unbedingt die Identität für die zuletzt hinzugefügte Zeile in einer Tabelle. Sie sollten immer SCOPE_IDENTITY () verwenden, um die Identität der kürzlich hinzugefügten Zeile zurückzugeben.


2

Welche Datenbank verwenden Sie? Soweit mir bekannt ist, gibt es dafür keine datenbankunabhängige Methode.


2

So habe ich es mit parametrisierten Befehlen gemacht.

MSSQL

 INSERT INTO MyTable (Field1, Field2) VALUES (@Value1, @Value2); 
 SELECT SCOPE_IDENTITY(); 

MySQL

 INSERT INTO MyTable (Field1, Field2) VALUES (?Value1, ?Value2);
 SELECT LAST_INSERT_ID();

2
sql = "INSERT INTO MyTable (Name) VALUES (@Name);" +
      "SELECT CAST(scope_identity() AS int)";
SqlCommand cmd = new SqlCommand(sql, conn);
int newId = (int)cmd.ExecuteScalar();

2

Frau SQL Server: Dies ist eine gute Lösung, auch wenn Sie mehr Zeilen einfügen:

 Declare @tblInsertedId table (Id int not null)

 INSERT INTO Test ([Title], [Text])
 OUTPUT inserted.Id INTO @tblInsertedId (Id)
 SELECT [Title], [Text] FROM AnotherTable

 select Id from @tblInsertedId 

1

Robs Antwort wäre die herstellerunabhängigste, aber wenn Sie MySQL verwenden , ist die integrierte LAST_INSERT_ID()Funktion die sicherere und korrektere Wahl .


0
SELECT @@Scope_Identity as Id

Es gibt auch eine @ @ Identität, aber wenn Sie einen Auslöser haben, werden die Ergebnisse von etwas zurückgegeben, das während des Auslösers passiert ist, wobei scope_identity Ihren Bereich respektiert.


0
  1. Fügen Sie die Zeile mit einer bekannten Anleitung ein.
  2. Holen Sie sich das AutoId-Feld mit dieser Anleitung.

Dies sollte mit jeder Art von Datenbank funktionieren.


0

Eine umweltbasierte Oracle-Lösung:

CREATE OR REPLACE PACKAGE LAST
AS
ID NUMBER;
FUNCTION IDENT RETURN NUMBER;
END;
/

CREATE OR REPLACE PACKAGE BODY LAST
AS
FUNCTION IDENT RETURN NUMBER IS
    BEGIN
    RETURN ID;
    END;
END;
/


CREATE TABLE Test (
       TestID            INTEGER ,
    Field1      int,
    Field2      int
)


CREATE SEQUENCE Test_seq
/
CREATE OR REPLACE TRIGGER Test_itrig
BEFORE INSERT ON Test
FOR EACH ROW
DECLARE
seq_val number;
BEGIN
IF :new.TestID IS NULL THEN
    SELECT Test_seq.nextval INTO seq_val FROM DUAL;
    :new.TestID := seq_val;
    Last.ID := seq_val;
END IF;
END;
/

To get next identity value:
SELECT LAST.IDENT FROM DUAL


0

Einfachste Antwort:

command.ExecuteScalar()

Standardmäßig wird die erste Spalte zurückgegeben

Rückgabewert Typ: System.Object Die erste Spalte der ersten Zeile in der Ergebnismenge oder eine Nullreferenz (Nothing in Visual Basic), wenn die Ergebnismenge leer ist. Gibt maximal 2033 Zeichen zurück.

Von MSDN kopiert

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.