简体   繁体   English

T-SQL EXEC和范围

[英]T-SQL EXEC and scope

Let's say I have a stored procedure with this in its body: 假设我的主体中有一个存储过程:

EXEC 'INSERT INTO ' + quotename(@table) ' blah...'
SELECT IDENT_CURRENT('' + @table + '')

Is IDENT_CURRENT() guaranteed to get the identity of that row INSERTed in the EXEC? IDENT_CURRENT()是否保证在EXEC中获得该行的标识? IDENT_CURRENT() "returns the last identity value generated for a specific table in any session and any scope", but the scope is different within the EXEC than the stored procedure, right? IDENT_CURRENT()“返回在任何会话和任何范围内为特定表生成的最后一个标识值”,但EXEC中的范围与存储过程不同,对吧?

I want to make sure that if the stored procedure is being called multiple times at once, the correct identity is SELECTed. 我想确保如果一次多次调用存储过程,则选择正确的标识。

EDIT: Or do I need to do both the INSERT and SELECT within the EXEC, like so: 编辑:或者我需要在EXEC中同时执行INSERT和SELECT,如下所示:

declare @insert nvarchar
set @insert = 
    'INSERT INTO ' + quotename(@table) ' blah...' +
    'SELECT IDENT_CURRENT(''' + @table + ''')'
EXEC @insert

And if that's the case, how do I SELECT the result of the EXEC if I want to continue with more code in T-SQL? 如果是这种情况,如果我想在T-SQL中继续使用更多代码,如何选择EXEC的结果? Like this (although it's obviously not correct): 像这样(虽然它显然不正确):

declare @insert nvarchar
set @insert = 
    'INSERT INTO ' + quotename(@table) ' blah...' +
    'SELECT IDENT_CURRENT(''' + @table + ''')'

declare @ident int
set @ident = EXEC @insert

-- more code
SELECT * FROM blah

UPDATE: In the very first snippet, if I SELECT SCOPE_IDENTITY() instead of using IDENT_CURRENT(), NULL is returned by the SELECT. 更新:在第一个片段中,如果我SELECT SCOPE_IDENTITY()而不是使用IDENT_CURRENT(),则SELECT返回NULL。 :( :(

Try 尝试

EXEC 'INSERT INTO ' + quotename(@table) ' blah...; SELECT @@IDENTITY'

or better, according to this 或者更好的,按照

EXEC 'INSERT INTO ' + quotename(@table) ' blah...; SELECT SCOPE_IDENTITY()'

According to Microsoft's T-SQL docs: 根据微软的T-SQL文档:

IDENT_CURRENT is similar to the SQL Server 2000 identity functions SCOPE_IDENTITY and @@IDENTITY. IDENT_CURRENT类似于SQL Server 2000身份函数SCOPE_IDENTITY和@@ IDENTITY。 All three functions return last-generated identity values. 所有三个函数都返回最后生成的标识值。 However, the scope and session on which last is defined in each of these functions differ: 但是,在每个函数中定义last的范围和会话有所不同:

IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope. IDENT_CURRENT返回在任何会话和任何范围内为特定表生成的最后一个标识值。

@@IDENTITY returns the last identity value generated for any table in the current session, across all scopes. @@ IDENTITY返回在所有范围内为当前会话中的任何表生成的最后一个标识值。

SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope. SCOPE_IDENTITY返回为当前会话中的任何表和当前范围生成的最后一个标识值。

So I would say, no, IDENT_CURRENT does not guarantee to give you back the right value. 所以我想说,不,IDENT_CURRENT 不能保证给你正确的价值。 It could be the last IDENTITY value inserted in a different session. 它可能是在不同会话中插入的最后一个IDENTITY值。

I would make sure to use SCOPE_IDENTITY instead - that should work reliably. 我会确保使用SCOPE_IDENTITY - 这应该可靠地工作。

Marc

http://blog.sqlauthority.com/2009/03/24/sql-server-2008-scope_identity-bug-with-multi-processor-parallel-plan-and-solution/ http://blog.sqlauthority.com/2009/03/24/sql-server-2008-scope_identity-bug-with-multi-processor-parallel-plan-and-solution/

There is a bug in SCOPE_IDENTITY() I have switched my stored procedures over to the methodology used to retrieve default values from an insert: SCOPE_IDENTITY()中存在一个错误我已将存储过程切换到用于从插入中检索默认值的方法:

 declare @TheNewIds table (Id bigint, Guid uniqueidentifier)
 insert [dbo].[TestTable] output inserted.Id, inserted.Guid into @TheNewIds
 values (default);
 select @Id = [Id], @Guid = [Guid] from @TheNewIds;

我认为Scope_Identity()是您正在寻找的,它将为您提供当前范围内的最新标识。

I'd like to chip in my favourite solution by using OUTPUT keyword. 我想通过使用OUTPUT关键字来填充我最喜欢的解决方案。 Since INSERT can support multiple rows at a time, we would want to know the identities inserted. 由于INSERT一次可以支持多行,我们希望知道插入的身份。 Here goes: 开始:

 
-- source table
if object_id('Source') is not null drop table Source
create table Source
(
    Value datetime
)
-- populate source
insert Source select getdate()
waitfor delay '00:00.1'
insert Source select getdate()
waitfor delay '00:00.1'
insert Source select getdate()
select * from Source -- test
-- destination table
if object_id('Destination') is null
create table Destination
(
    Id int identity(1, 1),
    Value datetime
)
-- tracking table to keep all generated Id by insertion of table Destination
if object_id('tempdb..#Track') is null
create table #Track 
(
    Id int  
)
else delete #Track
-- copy source into destination, track the Id using OUTPUT
insert Destination output inserted.Id into #Track select Value from Source
select Id from #Track -- list out all generated Ids

Go ahead to run this multiple times to feel how it works. 继续多次运行以了解它是如何工作的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM