【问题标题】:T-SQL EXEC and scopeT-SQL EXEC 和范围
【发布时间】:2009-04-08 21:02:18
【问题描述】:

假设我的主体中有一个存储过程:

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

IDENT_CURRENT() 是否保证在 EXEC 中获得插入行的标识? IDENT_CURRENT() “返回在任何会话和任何范围内为特定表生成的最后一个标识值”,但 EXEC 内的范围与存储过程不同,对吧?

我想确保如果存储过程同时被多次调用,则选择正确的标识。

编辑:或者我是否需要在 EXEC 中同时执行 INSERT 和 SELECT,如下所示:

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

如果是这种情况,如果我想继续使用 T-SQL 中的更多代码,我该如何选择 EXEC 的结果?像这样(虽然显然不正确):

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

更新:在第一个 sn-p 中,如果我选择 SCOPE_IDENTITY() 而不是使用 IDENT_CURRENT(),则 SELECT 将返回 NULL。 :(

【问题讨论】:

    标签: sql tsql scope identity


    【解决方案1】:

    试试

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

    或者更好,根据this

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

    【讨论】:

    • 强烈建议您使用第二个。 @@Identity 几乎不应该被使用,因为它通常不会给出正确的结果。感谢您认识到范围身份需要在 exec 语句中。
    【解决方案2】:

    根据微软的 T-SQL 文档:

    IDENT_CURRENT 类似于 SQL Server 2000 身份功能 SCOPE_IDENTITY 和@@IDENTITY。全部 三个函数返回最后生成的 身份值。然而,范围 和定义 last 的会话 在这些功能中的每一个都不同:

    IDENT_CURRENT 返回最后一个 为 a 生成的标识值 任何会话中的特定表和任何 范围。

    @@IDENTITY 返回最后一个身份 为任何表生成的值 当前会话,涵盖所有范围。

    SCOPE_IDENTITY 返回最后一个 为任何表生成的标识值 在当前会话和当前 范围。

    所以我会说,不,IDENT_CURRENT 确实保证给你正确的价值。它可能是在不同会话中插入的最后一个 IDENTITY 值。

    我会确保改用 SCOPE_IDENTITY - 这应该可以可靠地工作。

    马克

    【讨论】:

      【解决方案3】:

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

      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;
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          我想通过使用 OUTPUT 关键字加入我最喜欢的解决方案。由于 INSERT 一次可以支持多行,我们想知道插入的身份。如下:

           
          -- 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
          

          继续运行多次以感受其工作原理。

          【讨论】:

            猜你喜欢
            • 2013-10-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多