2012-04-12 10 views
30

Ho uno script che crea un intero database e inserisce tutti i record in alcune dozzine di tabelle. Funziona alla grande, a meno che non ci sia un problema durante l'elaborazione, e una tabella viene lasciata con IDENTITY_INSERT ON, quando lo script fallisce durante l'inserimento e prima che possa essere nuovamente impostato su OFF.Imposta IDENTITY_INSERT OFF per tutte le tabelle

Quando ciò accade, lo script fallisce automaticamente quando si tenta di eseguirlo di nuovo, con l'errore "IDENTITY_INSERT è già attivo per tabella xx" mentre entriamo nell'inserzione per la prima tabella.

Come sicurezza, mi piacerebbe assicurarsi che IDENTITY_INSERT sia impostato su OFF per tutte le tabelle, prima di eseguire il resto dell'elaborazione nello script di installazione.

In alternativa, potremmo forse chiudere la connessione MS SQL e aprirla di nuovo, che, a quanto ho capito, cancellerebbe tutti i valori IDENTITY_INSERT per la sessione di connessione.

Qual è il modo migliore per farlo e prevenire gli errori "già attivi"?

+0

Quale versione di SQL Server? –

+0

Questa app deve funzionare con il 2005 e oltre, quindi idealmente una soluzione che funziona per tutte le versioni recenti e future. –

+0

La mia soluzione di seguito dovrebbe funzionare tra 05 e successivi. –

risposta

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

Mi piace molto ... tranne, non tutte le tabelle in questo db hanno un campo identità, quindi questo fallisce. Altrimenti, sospetto che sarebbe perfetto. –

+1

In qualsiasi momento, solo una tabella in una sessione può avere la proprietà IDENTITY_INSERT impostata su ON in base a http://technet.microsoft.com/en-us/library/aa259221(v=sql.80).aspx # feedback – qub1n

+1

@ qub1n L'OP non ha chiesto di impostare la proprietà su ON. –

36

SQL dinamico:

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) 

quindi copiare & incollare il codice SQL risultante in un'altra finestra di query ed eseguire

+0

ti amo per aver condiviso questo, bel trucco comunque :) – ktutnik

+0

Wow, questo mi ha salvato il bacon. Grazie! –

+0

Voglio avere questo per il mio db di massa inserire dal mio codice. Puoi suggerire qualcosa su come ottenerlo in 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)' 

Sulla risposta di Lynn, nel caso in cui si è troppo pigri per esegui questo in più di un passaggio: questo dovrebbe essere eseguito su tutte le tabelle in cui è presente una colonna Identity.

avvertimento è testato solo nel 2012 e sp_MSforeachtable è naturalmente del tutto non supportato ...

+0

Funziona anche in Sql Server 2014 e 2016 –

1

Sulla base di @ KevD risposta - Si stava lavorando bene per la disabilitazione, ma qui è più per l'abilitazione pure.

Per disabilitare tutti gli inserti di identità in cui hanno bisogno per essere disabilitato, l'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''' 

per consentire a tutti gli inserti di identità in cui hanno bisogno di essere attivata, l'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''' 

provata su SQL server 2014 e 2016

0

Avevo un problema simile ma preferirei non utilizzare procedure memorizzate non documentate in produzione. Per automatizzare questo ho costruito la risposta di @John Dewey e l'ho messa in un cursore. Questo itera oltre 699 tabelle in 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 

Se sei contro i cursori, potrebbe anche essere facilmente trasformato in un ciclo while.

Problemi correlati