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?

Niyaz
quelle
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()

SQLMenace
quelle
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();
David Basarab
quelle
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.

UnkwnTech
quelle
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.

Daniel Schaffer
quelle
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();  
}  
Slartibartfast
quelle
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

Telcontar
quelle
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.

Neall
quelle
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.

Vincent Robert
quelle
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.

Nicht ich
quelle
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.

DBinukumar
quelle
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.

Espo
quelle
2

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

Matthew Watson
quelle
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();
Wyck Hebert
quelle
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();
James Lawruk
quelle
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 
Jan Remunda
quelle
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 .

Tobias Baaz
quelle
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.

Entwicklung von Chris
quelle
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.

Dummy
quelle
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

quelle
0

In TransactSQL können Sie die OUTPUT-Klausel verwenden, um dies zu erreichen.

INSERT INTO my_table(col1,col2,col3) OUTPUT INSERTED.id VALUES('col1Value','col2Value','col3Value')

FR: http://msdn.microsoft.com/en-us/library/ms177564.aspx

Super glücklich
quelle
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

LiranBo
quelle