【问题标题】:Getting new IDs after insert插入后获取新 ID
【发布时间】:2009-05-01 10:47:37
【问题描述】:

我将一堆新行插入到定义如下的表中:

CREATE TABLE [sometable](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [someval] sometype NOT NULL
)

使用以下插入:

insert into sometable select somefield as someval from othertable

完成后,我想知道所有新插入的行的 ID。 SCOPE_IDENTITY() 只返回最后插入的行的 ID。

如何获取所有新 ID?

想到的一种方法是从 sometable 和插入后的 scope_identity() 中获取当前最大的标识,并使用这两个值从 sometable 中进行选择。例如:

declare @currentMaxId int;
select @currentMaxId=MAX(id) from sometable
insert into sometable select somefield as someval from othertable
select * from sometable where id>@currentMaxId and id<=SCOPE_IDENTITY()

有更好的模式吗?

【问题讨论】:

    标签: sql sql-server insert identity


    【解决方案1】:

    使用 OUTPUT 功能将所有 INSERTED Id 抓取回表中。

    CREATE TABLE MyTable
    (
        MyPK INT IDENTITY(1,1) NOT NULL,
        MyColumn NVARCHAR(1000)
    )
    
    DECLARE @myNewPKTable TABLE (myNewPK INT)
    
    INSERT INTO 
        MyTable
    (
        MyColumn
    )
    OUTPUT INSERTED.MyPK INTO @myNewPKTable
    SELECT
        sysobjects.name
    FROM
        sysobjects
    
    SELECT * FROM @myNewPKTable
    

    【讨论】:

    • @Robin - 我已经使用 SQL Server 多年,但我从你的回答中学到了两个新东西,OUTPUT 和 TABLE 数据类型。谢谢。
    • 我也使用 SQL 大概 15 年了,不知道 OUTPUT 的存在,谢谢!
    • @Robin,这个问题可能听起来很傻,但是如果我在循环内的表“myNewPkTable”中检索这个主键值(在这种情况下是光标),这个值将被插入一行在那张桌子里面,是吗?
    • 这是 the 解决方案.....直到表包含触发器,然后您遇到 Microsoft 拒绝修复的错误(OUTPUT 不能没有INTO 在带有触发器的表中,并在使用 INTO 时给出错误值)。此处列出了解释和可能的解决方法(至少对于 UPDATE 案例):stackoverflow.com/q/13198476/2557263
    【解决方案2】:

    如果您想要 ADO.Net 中的“控制”并获取分配给子项的 id 并取回 id 以便您可以更新您的模型: http://daniel.wertheim.se/2010/10/24/c-batch-identity-inserts/

    【讨论】:

    • 链接不再有效。网站仍然有效,但只能通过 https 并且网站历史不会超过 2010 年 11 月 6 日。
    【解决方案3】:

    使用这个存储的过程

    这将是一个动态主键..

    
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_NULLS ON
    GO
    
    

    CREATE PROCEDURE sp_BulkInsertCountry ( @FilePath varchar(1000) ) AS BEGIN--PROCEDURE --variable declaration declare @SQL varchar(500) declare @id int declare @CountryName varchar(30)

    --Create temporary table for Country CREATE TABLE #tmpCountry ( CountryName varchar(30), )

    ---executing bulk insert on temporary table SET @SQL='BULK INSERT #tmpCountry from ''' + @FilePath + ''' WITH (FIELDTERMINATOR ='','',ROWTERMINATOR=''\n'')' EXEC(@sql)

    DECLARE cursor_Country CURSOR READ_ONLY FOR select [CountryName] from #tmpCountry

    OPEN cursor_Country FETCH NEXT FROM cursor_Country INTO @CountryName WHILE @@FETCH_STATUS=0 BEGIN SELECT @id=isnull(max(Countryid),0) from tblCountryMaster SET @id=@id+1 INSERT INTO tblCountryMaster values(@Id,@CountryName) FETCH NEXT FROM cursor_Country INTO @CountryName END CLOSE cursor_Country DEALLOCATE cursor_Country END--PROCEDURE

    GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO

    欲了解更多详情,请访问以下链接 http://jalpesh.blogspot.com/search?q=bulk+insert

    【讨论】:

      【解决方案4】:

      创建一个表来设置所有新的 ID。 然后为所有插入创建一个循环。 在循环内使用 SCOPE_IDENTITY() 进行插入。 插入后获取新 ID 并将其插入到您为其创建的新表中。 最后从 [newTable] 中选择 *。

      【讨论】:

        【解决方案5】:

        扩展@Robin Day 的答案——您可以使用 MERGE 技巧将您的临时 ID 映射到新 ID。

        DECLARE @Keys TABLE (TempId INT, RealId INT)
        
        MERGE MyTable
            USING @NewStuff t
            ON 1 = 0
            WHEN NOT MATCHED THEN
                INSERT (col1, col2, col3)
                VALUES (t.col1, t.col2, t.col3)
                OUTPUT t.TempId, Inserted.RealId INTO @Keys
        

        来自@Ivan Starostin 的巧妙回答: List of inserted ID in SQL Server

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-08
          • 2011-06-01
          • 1970-01-01
          相关资源
          最近更新 更多