我正在尝试在INSERT语句后找回键值。
示例:
我有一个带有属性名称和ID的表。 id是一个生成的值。

    INSERT INTO table (name) VALUES('bob');


现在我想在同一步骤中重新获得ID。如何完成?

我们正在使用Microsoft SQL Server2008。

评论

我在这里找到了一个有用的答案:[准备的语句与语句-返回-生成的键] [1] [1]:stackoverflow.com/questions/4224228 / ...

获取插入行身份的最佳方法的可能重复项?

#1 楼

不需要单独的SELECT ...

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');


这也适用于非IDENTITY列(例如GUID)

评论


你能详细说明一下吗?在此示例中,输出到哪里去了?该文档仅显示表示例(使用output ... into)。理想情况下,我只想将其传递给变量

–JonnyRaa
2014年4月8日在12:17

@JonnyLeeds:您不能对变量执行此操作(除非使用表变量)。输出转到客户端或表

– gbn
2014年4月8日在12:51

不幸的是,您不能依赖于此,因为向表添加触发器将破坏您的语句!回复:blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/…

– hajikelist
15年6月24日在21:22

@hajikelist:这是一个非常极端的情况,在触发器中将NCOOUNT ON设置通常会有所帮助。参见stackoverflow.com/questions/1483732/set-nocount-on-usage

– gbn
15年6月26日在9:19

请勿使用@@ IDENTITY。 SCOPE_IDENTITY,是的,但是永远不要@@ IDENTITY。不可靠

– gbn
17年10月10日在10:28

#2 楼

使用SCOPE_IDENTITY()获取新的ID值

INSERT INTO table (name) VALUES('bob');

SELECT SCOPE_IDENTITY()


http://msdn.microsoft.com/zh-cn/library/ms190315.aspx

评论


@ liho1eye-OP将标识列名称称为id,所以是的。


2011-10-27 14:50



在较大的系统上,如果同时运行多个sql怎么办?它将为每个请求返回最后插入的ID吗?

– Shiv
17年5月5日在13:59

@Shiv“ SCOPE_IDENTITY返回仅在当前范围内插入的值”

– goodies4uall
17年12月14日在15:44

#3 楼

INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();


是最安全的选择,因为带有触发器的表上存在一个已知的OUTPUT子句冲突问题。即使您的表当前没有任何触发器,也使此操作非常不可靠-一行添加一个触发器将破坏您的应用程序。定时炸弹行为。

请参阅msdn文章以获得更深入的说明:

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11 /update-with-output-clause-triggers-and-sqlmoreresults.aspx

评论


仅当您未在触发器中添加SET NOCOUNT ON时。另请参阅docs.microsoft.com/zh-cn/sql/database-engine/configure-windows/…

– gbn
18年3月13日在8:48

这不是我们的旧环境@gbn的选项

– hajikelist
18-3-16的3:16

@hajikelist我们都有传承,但是触发器搞乱OUTPUT的风险很低,只需要设置nocount就可以了。如果有人要添加触发器,那么他们应该知道如何对其进行编码(这主要意味着您具有控制权),或者您需要培训开发人员。支持等,因此触发器不会导致结果集。无论如何,这不是最佳答案,因为如果您具有INSTEAD OF触发器,则SCOPE_IDENTITY可能无法正常工作(stackoverflow.com/questions/908257/…)

– gbn
18-3-16在7:35



@gbn-我只是想避免像这样的愚蠢的事情。我不会告诉所有开发人员,“不要忘记在每个触发器中添加'不要破坏我的应用程序声明'。” - 你可以留着。 “代替”方案远不止是边缘情况。

– hajikelist
18 Mar 16 '18 at 17:39

一个更安全的答案可能就是让应用程序从该查询返回后再运行另一个查询。只要在后端完成,性能损失就值得在一群人中管理开发的简单性,并且按照标准,它比带有边缘案例的某些疯狂功能更接近标准。我宁愿边缘情况出现在我的代码中,并避免在平台上使用它们。只是我的意见不惊吓:)

–丹·蔡斯(Dan Chase)
18/09/21在14:22

#4 楼

实体框架执行的操作类似于gbn的答案:

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO @generated_keys
VALUES('bob');

SELECT t.[CustomerID]
FROM @generated_keys AS g 
   JOIN dbo.Customers AS t 
   ON g.Id = t.CustomerID
WHERE @@ROWCOUNT > 0


输出结果存储在临时表变量中,然后选择返回给客户端。必须注意的问题:


插入可以生成多行,因此该变量可以容纳多行,因此可以返回多个ID


我不知道为什么EF会将内部临时表重新连接到真实表(在什么情况下两者不匹配)。

但这就是EF所做的。

仅SQL Server 2008或更高版本。如果是2005年,那您真不走运。

评论


EF之所以这样做,是为了确保它也可以“看到”对插入的客户记录的所有其他更改,因为可能会有其他DB端逻辑对其产生影响,例如在某些列上使用DEFAULT,在表上使用触发器,等等。EF更新用于插入的实体(对象),以便客户端获取具有ID的客户对象以及代表行当前状态的其他所有对象。

– Hilarion
20-2-18在15:25



不使用EF的另一个原因。

– cskwg
20-2-24在7:13

#5 楼

@@IDENTITY是一个系统函数,它返回最后插入的标识值。

评论


必须建议不要使用@@ IDENTITY-它不准确(太宽泛),线程安全性要差得多-请参阅@Curt关于SCOPE_IDENTITY()的回答。

– zanlok
'18 Apr 16在23:37



#6 楼

插入后有多种退出方法


将数据插入表中时,可以使用OUTPUT子句
返回已插入到表中的数据的副本。表。
OUTPUT子句采用两种基本形式:OUTPUT和OUTPUT INTO。如果要将数据返回到调用应用程序,请使用
OUTPUT表单。如果要将数据返回到表或表变量,请使用OUTPUT INTO表单。
/>

DECLARE @MyTableVar TABLE (id INT,NAME NVARCHAR(50));

INSERT INTO tableName
(
  NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO @MyTableVar
VALUES
(
   'test',...
)


IDENT_CURRENT:它返回在任何会话中为特定表或视图创建的最后一个标识。


SCOPE_IDENTITY:它返回来自同一会话和相同范围的最后一个身份。作用域是存储过程/触发器等。

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]


@@ IDENTITY:它返回同一会话中的最后一个标识。

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  


评论


@RezaJenabi Jun,输出效果很好,胜于在表中找到许多ID。我用了put来进行大容量插入,并用select语句插入。谢谢你的建议

–阿米尔侯赛因
20 Apr 25'5:58

#7 楼

最好,最确定的解决方案是使用SCOPE_IDENTITY()

每次插入后都必须获得作用域标识并将其保存在变量中,因为您可以在同一作用域中调用两个insert。

ident_current@@identity可能是可以工作的,但它们不是安全范围。您可能在大型应用程序中遇到问题

  declare @duplicataId int
  select @duplicataId =   (SELECT SCOPE_IDENTITY())


此处有更多详细信息Microsoft文档

评论


可以简化为选择@duplicataId = SCOPE_IDENTITY()

–pcnate
18-10-26在13:45

OUTPUT子句是一种更好,更纯净的解决方案:)

–戴尔K
19-09-15在22:29

输出进入非常慢。

– cskwg
20-2-24在7:11

#8 楼

您可以使用scope_identity()选择刚刚插入变量中的行的ID,然后从该表中选择所需的列,其中id =从scope_identity()获得的标识。信息http://msdn.microsoft.com/zh-cn/library/ms190315.aspx

#9 楼

在插入命令之后,有多种方法来获取最后插入的ID。



@@IDENTITY:无论表和表如何,它都会返回在当前会话中的Connection上生成的最后一个Identity值。产生值的语句的作用域

SCOPE_IDENTITY():它返回由insert语句在当前连接的当前作用域中在当前连接中生成的最后一个标识值,而不管表是什么。

IDENT_CURRENT(‘TABLENAME’):它返回在指定表上生成的最后一个标识值,而不管任何连接,会话或作用域如何。 IDENT_CURRENT不受范围和会话的限制;它仅限于指定的表。

现在,要确定哪一个将完全符合我的要求似乎更加困难。

我最喜欢SCOPE_IDENTITY()。

如果您在insert语句中使用select SCOPE_IDENTITY()和TableName一起使用,您将根据您的期望获得准确的结果。

来源:CodoBee

#10 楼

当插入到使用ID作为SQL Server中的标识列的表时,这就是我使用OUTPUT INSERTED的方式:

'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)


#11 楼

您可以将select语句追加到insert语句。
Integer myInt =
插入到table1(FName)values('Fred');中。选择Scope_Identity();
执行缩放器时将返回该身份的值。

#12 楼

在具有标识列的表中插入后,可以引用@@ IDENTITY以获取值:
http://msdn.microsoft.com/zh-cn/library/aa933167%28v=sql.80 %29.aspx

评论


切勿使用@@ IDENTITY:这不是范围安全的:触发器等会对其产生影响。

– gbn
2011-10-27 14:56

#13 楼

*连接字符串中的参数顺序有时很重要。 *提供者参数的位置可以在添加一行后中断记录集游标。我们在SQLOLEDB提供程序中看到了这种行为。

添加行后,行字段不可用,除非将提供程序指定为连接字符串中的第一个参数。当提供程序位于连接字符串中除第一个参数以外的任何位置时,新插入的行字段将不可用。当我们将Provider移到第一个参数时,行字段神奇地出现了。

评论


您能否告诉我们此评论如何回答/与所提问题相关?我觉得这不应该大写/加粗。如果您的回答被认为是有帮助的,则用户会投票赞成。

– n__o
15年8月5日在22:01

许多用户可能因为没有有效的字段来标识刚刚添加的行而来到此页面。我们发现的这种行为(只需更改连接字符串中参数的顺序就可以立即访问新添加的行)是如此奇怪,以至于我认为值得大写,特别是因为这很可能会解决人们想要新的行列的原因。行ID和该行的其他字段。通过简单地将提供者作为第一个参数,问题就消失了。

–大卫·吉多斯(David Guidos)
15年8月6日在23:55

您需要编辑和改善答案。它目前很吵,不会作为一个不错的答案甚至是尝试

–詹姆斯
15年8月31日在18:46

您所说的“嘈杂”到底是什么意思?您需要解释您的投诉。它尽可能简单。如果更改连接字符串中参数的顺序,则会影响插入后行数据是否可用。

–大卫·吉多斯(David Guidos)
2015年9月1日21:32在