SQL:如何获得我刚刚插入的值的ID?
我在表中插入了一些值。 有一列值是自动生成的。 在我的代码的下一个声明中,我想要检索这个值。
你能告诉我如何正确地做到这一点吗?
@@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();
如果你使用PHP和MySQL,你可以使用mysql_insert_id()函数来告诉你刚刚受到干扰的项目的ID。
但是没有你的语言和DBMS,我只是在黑暗中拍摄而已。
这在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(); }
如果您正在使用Oracle:
插入表(字段….)值(值…)返回(字段列表…)INTO(variables…)
例:
插入人(姓名)值('杰克')返回ID_PERSON INTO被访问者
或者如果你正在调用Java … CallableStatement(sry,这是我的领域)
插入人(姓名)值('杰克')返回ID_PERSON INTO?
并为语句声明一个autput参数
没有标准的方法来做(就像没有标准的方法来创build自动递增的ID一样)。 这里有两种方法可以在PostgreSQL中完成。 假设这是你的表格:
CREATE TABLE mytable ( id SERIAL PRIMARY KEY, lastname VARCHAR NOT NULL, firstname VARCHAR );
只要它们在同一个连接中是连续的语句,就可以用两个语句来完成(这在连接池中是安全的,因为在连接脚本完成之前PHP不会将连接返回到池):
INSERT INTO mytable (lastname, firstname) VALUES ('Washington', 'George'); SELECT lastval();
lastval()为您提供当前连接中使用的最后一个自动生成的序列值。
另一种方法是在INSERT语句中使用PostgreSQL的RETURNING子句:
INSERT INTO mytable (lastname) VALUES ('Cher') RETURNING id;
这种forms就像SELECT语句一样返回一个结果集,也可以方便地返回任何计算的默认值。
一个重要的注意事项是使用供应商的SQL查询来检索最后插入的ID是安全的,而不用担心并发连接。
我一直认为你必须创build一个事务,以便插入一行,然后select最后插入的ID,以避免检索另一个客户端插入的ID。
但是这些特定于供应商的查询总是检索当前连接到数据库的最后插入的ID。 这意味着只要使用自己的数据库连接,最后插入的ID不会受到其他客户端插入的影响。
从网站上我发现了以下几点:
SQL SERVER – @@ IDENTITY vs SCOPE_IDENTITY()与IDENT_CURRENT – 检索logging的最后插入的标识 2007年3月25日,由pinaldave
SELECT @@ IDENTITY它返回连接上产生的最后一个IDENTITY值,而不pipe产生该值的表是什么,也不pipe产生该值的语句的范围如何。 @@ IDENTITY将返回在当前会话中input到表中的最后一个标识值。 虽然@@ IDENTITY仅限于当前会话,但不限于当前范围。 如果在表上有一个触发器,导致在另一个表中创build一个标识,那么即使它是创build它的触发器,也会得到最后创build的标识。
SELECT SCOPE_IDENTITY()它返回连接和同一范围内的语句生成的最后一个IDENTITY值,而不pipe产生该值的表。 SCOPE_IDENTITY(),如@@ IDENTITY,将返回当前会话中创build的最后一个标识值,但也会将其限制在当前范围内。 换句话说,它将返回您显式创build的最后一个标识值,而不是由触发器或用户定义函数创build的任何标识。
SELECT IDENT_CURRENT('tablename')它返回表中生成的最后一个IDENTITY值,而不pipe创build值的连接如何,也不pipe产生该值的语句的范围如何。 IDENT_CURRENT不受范围和会话的限制; 它仅限于指定的表格。 IDENT_CURRENT返回为任何会话和任何作用域中的特定表生成的标识值。
对于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列的值。
请记住,@@ IDENTITY返回当前连接的最近创build的标识,而不一定是表中最近添加的行的标识。 您应始终使用SCOPE_IDENTITY()返回最近添加的行的标识。
你在用什么数据库? 据我所知,没有数据库不可知的方法来做到这一点。
这是我使用参数化命令完成的。
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();
sql = "INSERT INTO MyTable (Name) VALUES (@Name);" + "SELECT CAST(scope_identity() AS int)"; SqlCommand cmd = new SqlCommand(sql, conn); int newId = (int)cmd.ExecuteScalar();
Ms SQL Server:即使插入更多行,这也是一个很好的解决scheme:
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
Rob的答案是最不依赖厂商的,但是如果你使用的是MySQL,那么安全和正确的select就是内置的LAST_INSERT_ID()
函数。
SELECT @@Scope_Identity as Id
还有@@身份,但是如果你有一个触发器,它将返回触发器发生的事情的结果,其中scope_identity尊重你的范围。
- 用已知的guid插入行。
- 用这个GUID获取autoId字段。
这应该适用于任何types的数据库。
基于环境的Oracle解决scheme:
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')
FRI: http : //msdn.microsoft.com/en-us/library/ms177564.aspx
最简单的答案:
command.ExecuteScalar()
默认情况下返回第一列
返回值types:System.Object结果集中第一行的第一列,如果结果集为空,则为null引用(在Visual Basic中为Nothing)。 返回最多2033个字符。
从MSDN复制
- 如何在使用SQL Server 2008的情况下使用多个CASE?
- 布尔值与tinyint(1)在MySQL中的布尔值
- 是否有可能在SQLite数据库中一次插入多行?
- 如何抑制SQL Server中另一个存储过程调用的存储过程的SELECT输出?
- 如何在SQL Server数据库中添加一个auto_increment主键?
- Linq版本的SQL“IN”语句
- 当我尝试使用sp_executesql时,为什么会得到“Procedure expectpects parameter”@statement“types为”ntext / nchar / nvarchar“。
- SQL:总和3列时,一列有一个空值?
- TSQL中的COALESCE函数