我有一个脚本可以创建一个完整的数据库并将所有记录插入到几十个表中。 它工作得很好,除非在处理期间出现一些问题,并且当一个表在IDATITY_INSERT ON时,当脚本在插入期间失败并且可以再次设置为OFF之前,它将保持打开状态。
当发生这种情况时,脚本会在尝试再次运行时自动失败,当我们进入第一个表的插入时,错误“IDENTITY_INSERT已经为表xx打开”。
作为故障保护,我想确保在运行安装脚本中的其余处理之前,将所有表的IDENTITY_INSERT设置为OFF。
作为替代方案,我们可以关闭MS SQL连接并再次打开它,据我所知,它将清除连接会话的所有IDENTITY_INSERT值。
最好的方法是什么,并防止“已经开启”错误?
答案 0 :(得分:44)
动态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粘贴到另一个查询窗口并运行
答案 1 :(得分:18)
EXEC sp_MSforeachtable @command1="SET IDENTITY_INSERT ? OFF"
答案 2 :(得分:6)
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 当然完全不受支持......
答案 3 :(得分:2)
以@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上测试
答案 4 :(得分:0)
我有类似的问题,但我不想在生产中使用未记录的存储过程。为了实现自动化,我建立了@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循环。