37

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

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

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

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

做到这一点并防止“已经启动”错误的最佳方法是什么?

4

5 回答 5

53

动态 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 复制并粘贴到另一个查询窗口并运行

于 2012-04-12T02:58:02.400 回答
19
EXEC sp_MSforeachtable @command1="SET IDENTITY_INSERT ? OFF"
于 2012-04-12T02:55:31.173 回答
8
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 的回答为基础,以防您懒得在多个步骤中执行此操作 - 这应该在所有有标识列的表上运行。

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

于 2016-11-18T15:02:31.857 回答
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 上测试

于 2017-10-18T16:19:37.070 回答
0

我有一个类似的问题,但我宁愿不在生产中使用未记录的存储过程。为了自动化这个我建立在@John Dewey's answer并将它放入游标中。这在 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 循环。

于 2018-02-13T18:44:31.143 回答