我在表中插入了一些值。有一个其值是自动生成的列。在我的代码的下一个语句中,我想检索此值。
你能告诉我如何正确地做吗?
Answers:
@@IDENTITY
是不安全的,如果您在原始表上有插入触发器,则会使您从另一个表中获取ID,请务必使用 SCOPE_IDENTITY()
这就是我使用自动生成的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();
这在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的好处。
同样,没有语言不可知的响应,但是在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();
}
没有标准的方法(就像没有创建自动增量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语句一样返回结果集,并且对于返回任何一种计算出的默认值也很方便。
对于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 – @@ 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返回在任何会话和任何作用域中为特定表生成的标识值。
Rob的答案将是与供应商最不相关的,但是,如果您使用的是MySQL,则内置的LAST_INSERT_ID()
功能将是更安全正确的选择。
基于环境的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
在TransactSQL中,可以使用OUTPUT子句来实现。
INSERT INTO my_table(col1,col2,col3) OUTPUT INSERTED.id VALUES('col1Value','col2Value','col3Value')