【问题标题】:Set IDENTITY_INSERT OFF for all tables为所有表设置 IDENTITY_INSERT OFF
【发布时间】:2012-04-24 09:31:19
【问题描述】:

我有一个脚本,它创建一个完整的数据库并将所有记录插入到几十个表中。 它工作得很好,除非在处理过程中出现一些问题,并且当脚本在插入过程中失败并且可以再次将其设置为 OFF 之前,表格会留下 IDENTITY_INSERT ON。

发生这种情况时,脚本会在尝试再次运行时自动失败,并在我们进入第一个表的插入时出现错误“IDENTITY_INSERT is already ON for table xx”。

作为故障保险,我想确保在设置脚本中运行其余处理之前,将所有表的 IDENTITY_INSERT 设置为 OFF。

作为替代方案,我们或许可以关闭 MS SQL 连接并再次打开它,据我了解,这会清除连接会话的所有 IDENTITY_INSERT 值。

什么是最好的方法来做到这一点,并防止“已经开始”的错误?

【问题讨论】:

  • 此应用需要在 2005 及更高版本上运行,因此理想的解决方案适用于所有最近和即将推出的版本。
  • 我下面的解决方案应该适用于 05 及更高版本。

标签: sql sql-server


【解决方案1】:
EXEC sp_MSforeachtable @command1="SET IDENTITY_INSERT ? OFF"

【讨论】:

  • 我非常喜欢这个......除了,不是这个数据库中的每个表都有一个身份字段,所以这失败了。否则我怀疑它会是完美的。
  • 根据technet.microsoft.com/en-us/library/…,在任何时候,会话中只有一个表可以将IDENTITY_INSERT属性设置为ON
  • @qub1n OP 没有要求将属性设置为 ON。
  • 我知道它没有任务,但我希望它对像我一样正在寻找 SET IDENTITY_INSERT ON 的人有用。
【解决方案2】:

动态 SQL:

select 'set identity_insert ['+s.name+'].['+o.name+'] off'
from sys.objects o
inner join sys.schemas s on s.schema_id=o.schema_id
where o.[type]='U'
and exists(select 1 from sys.columns where object_id=o.object_id and is_identity=1)

然后将生成的 SQL 复制并粘贴到另一个查询窗口并运行

【讨论】:

  • 哇,这救了我的培根。谢谢!
  • 我想从我的代码中为我的批量数据库插入这个。你能提出一些如何在 jpa 中实现这一目标的建议吗?
【解决方案3】:
EXEC sp_MSforeachtable @command1="PRINT '?'; SET IDENTITY_INSERT ? OFF",
@whereand = ' AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = o.id  AND is_identity = 1)'

以 Lynn 的回答为基础,以防您懒得在多个步骤中执行此操作 - 这应该在所有有标识列的表上运行。

Caveat 仅在 2012 年进行了测试,sp_MSforeachtable 当然完全不受支持...

【讨论】:

    【解决方案4】:

    以@KevD 的回答为基础 - 禁用时效果很好,但启用时也有更多功能。

    要禁用所有需要禁用的身份插入,请使用 -

    EXEC sp_MSforeachtable @command1="PRINT '?'; SET IDENTITY_INSERT ? OFF",
    @whereand = ' AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = o.id  
    AND is_identity = 1) and o.type = ''U'''
    

    要启用所有需要启用的身份插入,请使用 -

    EXEC sp_MSforeachtable @command1="PRINT '?'; SET IDENTITY_INSERT ? ON",
    @whereand = ' AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = o.id  
    AND is_identity = 1) and o.type = ''U'''
    

    在 Sql server 2014 和 2016 上测试

    【讨论】:

    • 如果已经开启,开启失败,退出执行。有没有办法先测试一下?
    【解决方案5】:

    我遇到了类似的问题,但我不想在生产中使用未记录的存储过程。为了自动化这一点,我建立在@John Dewey 的答案上并将其放入游标中。这会在 407 毫秒内迭代超过 699 个表。

    DECLARE @sql NVARCHAR(500) -- SQL command to execute
    
    DECLARE sql_cursor CURSOR LOCAL FAST_FORWARD FOR
    SELECT 'SET identity_insert ['+s.name+'].['+o.name+'] OFF'
    FROM sys.objects o
    INNER JOIN sys.schemas s on s.schema_id=o.schema_id
    WHERE o.[type]='U'
    AND EXISTS(SELECT 1 FROM sys.columns WHERE object_id=o.object_id AND is_identity=1)
    
    OPEN sql_cursor
    FETCH NEXT FROM sql_cursor INTO @sql
    
    WHILE @@FETCH_STATUS = 0
        BEGIN
            EXECUTE sp_executesql @sql  --> Comment this out to test
            -- PRINT @sql   --> Uncomment to test or if logging is desired
            FETCH NEXT FROM sql_cursor INTO @sql
        END
    
    CLOSE sql_cursor
    DEALLOCATE sql_cursor
    

    如果你反对游标,它也可以很容易地转换成一个while循环。

    【讨论】:

      猜你喜欢
      • 2013-06-09
      • 1970-01-01
      • 2021-08-27
      • 2015-10-18
      • 1970-01-01
      • 2011-10-02
      • 2018-05-27
      • 2010-10-01
      • 2011-03-07
      相关资源
      最近更新 更多