2012-04-12 30 views
30

Tengo un script que crea una base de datos completa e inserta todos los registros en unas pocas docenas de tablas. Funciona de maravilla, a menos que haya algún problema durante el procesamiento, y una tabla queda con IDENTITY_INSERT ON, cuando el script falla durante la inserción y antes de que se pueda establecer en OFF nuevamente.Establecer IDENTITY_INSERT OFF para todas las tablas

Cuando esto sucede, el script falla automáticamente al intentar ejecutarlo de nuevo, con el error "IDENTITY_INSERT ya está activado para la tabla xx" a medida que avanzamos en la inserción de la primera tabla.

Como solución de seguridad, me gustaría asegurarme de que IDENTITY_INSERT esté desactivado para todas las tablas, antes de ejecutar el resto del proceso en la secuencia de comandos de instalación.

Como alternativa, quizás podríamos cerrar la conexión MS SQL y abrirla de nuevo, lo que, según tengo entendido, borrará todos los valores IDENTITY_INSERT para la sesión de conexión.

¿Cuál es la mejor manera de hacer esto y evitar los errores "ya encendidos"?

+0

¿Qué versión de SQL Server? –

+0

Esta aplicación necesita funcionar con el año 2005 y superior, por lo que idealmente es una solución que funciona para todas las versiones recientes y futuras. –

+0

Mi solución a continuación debería funcionar en 05 y posteriores. –

Respuesta

18
EXEC sp_MSforeachtable @command1="SET IDENTITY_INSERT ? OFF" 
+3

Me gusta mucho ... excepto que no todas las tablas en este archivo db tienen un campo de identidad, por lo que esto falla. De lo contrario, sospecho que sería perfecto. –

+1

En cualquier momento, solo una tabla en una sesión puede tener la propiedad IDENTITY_INSERT configurada en ON según http://technet.microsoft.com/en-us/library/aa259221(v=sql.80).aspx # feedback – qub1n

+1

@ qub1n El OP no solicitó establecer la propiedad en ON. –

36

SQL dinámico:

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) 

luego copiar & pegar el código SQL resultante en otra ventana de consulta y ejecute

+0

te echo en falta por compartir esto, buen truco de todos modos :) – ktutnik

+0

Guau, esto me salvó el tocino. ¡Gracias! –

+0

Quiero tener esto para mi inserción db a granel de mi código. ¿Puedes sugerir algo cómo lograr eso en jpa? – muasif80

5
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)' 

Sobre la base de la respuesta de Lynn, en caso de que es demasiado perezoso para realice esto en más de un paso: esto debería ejecutarse en todas las tablas donde hay una columna de identidad.

Advertencia Sólo se prueba en 2012 y sp_MSforeachtable es, por supuesto, totalmente sin apoyo ...

+0

También funciona en Sql Server 2014 y 2016 –

1

Sobre la respuesta de @ KevD - Se estaba trabajando bien para inhabilitar pero aquí es más para permitir así.

Para desactivar todas las inserciones de identidad en las que necesitan ser inhabilitado, el uso -

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

para que todas las inserciones de identidad donde tienen que estar habilitado, el uso -

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

probado en el servidor SQL 2014 y 2016

0

Tuve un problema similar, pero preferiría no utilizar procedimientos almacenados no documentados en producción. Para automatizar esto, me basé en la respuesta de @John Dewey y la puse en un cursor. Esto itera más de 699 tablas en 407 ms.

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 

Si está en contra de los cursores, también podría transformarse fácilmente en un bucle while.

Cuestiones relacionadas