SQL:如何获取我刚刚插入的值的ID?


76

我在表中插入了一些值。有一个其值是自动生成的列。在我的代码的下一个语句中,我想检索此值。

你能告诉我如何正确地做吗?


6
如果您提供有关使用哪种数据库的详细信息,这将有所帮助。
Dhaust

Answers:


57

@@IDENTITY 是不安全的,如果您在原始表上有插入触发器,则会使您从另一个表中获取ID,请务必使用 SCOPE_IDENTITY()


2
sql server 2005中有SCOPE_IDENTITY()的已知错误,不确定2008年是否存在,如果需要,OUTPUT子句可以返回一组ID
KM。

1
SCOPE_IDENTITY()的已知错误返回错误值:blog.sqlauthority.com/2009/03/24/…解决方法是不在多处理器并行计划中运行INSERT或使用OUTPUT子句
KM。

4
该URL被@KM截断。因此希望此链接有效:具有多处理器并行计划和解决方案的SCOPE_IDENTITY错误
James Skemp

29

这就是我使用自动生成的ID进行MSSQL存储过程的方式。

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

如果您使用PHP和MySQL,则可以使用mysql_insert_id()函数,该函数将告诉您刚刚插入的项目的ID。
但是如果没有您的语言和DBMS,我只是在黑暗中拍摄。


14

这在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)

如果您的INSERT语句插入多行,则具有返回所有ID的好处。


11

同样,没有语言不可知的响应,但是在Java中,它是这样的:

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();  
}  

好的,我只是在寻找这个
raupach

8

如果您正在使用Oracle:

插入表(Fields ....)值(Values ...)返回(Fields ...)INTO(变量...)

例:

插入个人(名称)值(“ JACK”),并将ID_PERSON返回到vIdPerson

或者,如果您是从...使用CallableStatement进行Java调用(很抱歉,这是我的领域)

插入人(姓名)值(“ JACK”)并返回ID_PERSON?

并声明该语句的自变量参数


6

没有标准的方法(就像没有创建自动增量ID的标准方法一样)。这是在PostgreSQL中执行此操作的两种方法。假设这是您的表:

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

只要它们是同一连接中的连续语句,就可以在两个语句中执行此操作(在带有连接池的PHP中这是安全的,因为在脚本完成之前,PHP不会将连接返回给池):

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

lastval()为您提供当前连接中使用的最后一个自动生成的序列值。

另一种方法是在INSERT语句上使用PostgreSQL的RETURNING子句:

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

这种形式就像SELECT语句一样返回结果集,并且对于返回任何一种计算出的默认值也很方便。


这个返回的ID将为Java赋予Resultset对象的权限?
Ankur Loriya'4

4

重要说明是,使用供应商SQL查询来检索最后插入的ID是安全的,而不必担心并发连接。

我一直以为您必须创建一个事务才能插入一行,然后选择最后插入的ID,以避免检索另一个客户端插入的ID。

但是这些特定于供应商的查询始终会检索到当前与数据库的连接的最后插入的ID 。这意味着最后插入的ID不会受到其他客户端插入的影响,只要它们使用自己的数据库连接即可。


4

对于SQL 2005:

假设下表定义:

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

您可以使用以下内容:

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

它将返回ID列的值。


在较新的SQL Server版本中,此方法仍然有效。
dub stylee

4

从该网站我发现了以下内容:

SQL Server – @@ IDENTITY与SCOPE_IDENTITY()与IDENT_CURRENT –检索记录的最后插入的标识 ,2007年3月25日,作者pinaldave

SELECT @@ IDENTITY它将返回在连接上生成的最后一个IDENTITY值,而不管生成该值的表如何,以及生成该值的语句的范围如何。@@ IDENTITY将返回当前会话中输入到表中的最后一个身份值。虽然@@ IDENTITY仅限于当前会话,但不限于当前范围。如果您在一个表上有一个触发器,导致要在另一个表中创建一个标识,则即使创建它的触发器,您也会获得最后创建的标识。

SELECT SCOPE_IDENTITY()返回由连接和同一作用域中的语句产生的最后一个IDENTITY值,而不管产生该值的表如何。与@@ IDENTITY一样,SCOPE_IDENTITY()将返回在当前会话中创建的最后一个标识值,但也会将其限制为当前作用域。换句话说,它将返回您显式创建的最后一个标识值,而不是由触发器或用户定义的函数创建的任何标识。

SELECT IDENT_CURRENT('tablename')它将返回表中生成的最后一个IDENTITY值,而与创建该值的连接以及生成该值的语句的范围无关。IDENT_CURRENT不受范围和会话的限制;它仅限于指定的表。IDENT_CURRENT返回在任何会话和任何作用域中为特定表生成的标识值。


感谢您的解释!
doug 2012年

2

请记住,@@ IDENTITY返回当前连接的最新创建的标识,而不必返回表中最近添加的行的标识。您应该始终使用SCOPE_IDENTITY()返回最近添加的行的标识。


2

您正在使用什么数据库?据我所知,没有数据库不可知的方法来执行此操作。


2

这就是我使用参数化命令完成的方式。

微软SQL

 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

SQL Server女士:即使您插入更多行,这也是一个很好的解决方案:

 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 


0
SELECT @@Scope_Identity as Id

还有@@ identity,但是如果您有触发器,它将返回在触发器期间发生的事情的结果,其中scope_identity尊重您的范围。


0
  1. 插入具有已知GUID的行。
  2. 使用此向导获取autoId字段。

这适用于任何类型的数据库。


0

基于环境的Oracle解决方案:

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

最简单的答案:

command.ExecuteScalar()

默认情况下返回第一列

返回值类型:System Object在结果集中的第一行的第一列;如果结果集为空,则为空引用(在Visual Basic中为Nothing)。最多返回2033个字符。

MSDN复制

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.