2012-04-12 18 views
30

Mam skrypt, który tworzy całą bazę danych i wstawia wszystkie rekordy do kilkudziesięciu tabel. Działa wspaniale, chyba że wystąpi jakiś problem podczas przetwarzania, a tabela zostanie pozostawiona z IDENTITY_INSERT ON, gdy skrypt ulegnie uszkodzeniu podczas wstawiania i zanim będzie można go ponownie wyłączyć.Ustaw IDENTITY_INSERT OFF dla wszystkich tabel

Kiedy to się dzieje, skrypt automatycznie zawiedzie przy próbie uruchomienia go ponownie, z błędem "IDENTITY_INSERT jest już włączony dla tabeli xx", gdy wchodzimy do wstawiania dla pierwszej tabeli.

Jako zabezpieczenie przed uszkodzeniem chciałbym się upewnić, że IDENTITY_INSERT jest ustawione na WYŁ. Dla wszystkich tabel, przed uruchomieniem reszty przetwarzania w skrypcie instalacyjnym.

Jako alternatywę, moglibyśmy ewentualnie zamknąć połączenie MS SQL i otworzyć je ponownie, co, jak rozumiem, wyczyściłoby wszystkie wartości IDENTITY_INSERT dla sesji połączenia.

Jaki jest najlepszy sposób, aby to zrobić i zapobiec błędom "już trwają"?

+0

Jaką wersję programu SQL Server? –

+0

Ta aplikacja musi działać w wersji 2005 i nowszych, więc najlepiej jest znaleźć rozwiązanie dla wszystkich najnowszych i nadchodzących wersji. –

+0

Moje poniższe rozwiązanie powinno działać w wersji 05 i późniejszych. –

Odpowiedz

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

Bardzo to lubię ... z wyjątkiem, że nie każda tabela w tej db ma pole tożsamości, więc to się nie udaje. W przeciwnym razie podejrzewam, że byłby idealny. –

+1

W każdej chwili tylko jedna tabela w sesji może mieć ustawioną właściwość IDENTITY_INSERT na WŁĄCZ według http://technet.microsoft.com/en-us/library/aa259221(v=sql.80).aspx # feedback – qub1n

+1

@ qub1n OP nie poprosił o ustawienie właściwości na WŁ. –

36

Dynamiczny 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) 

Następnie skopiuj & wklej wygenerowany kod SQL w innym oknie zapytań i uruchomić

+0

hank za podzielenie się tym, miłym trikiem i tak :) – ktutnik

+0

Wow, to uratowało mi boczek. Dzięki! –

+0

Chcę, aby to było dla mojej luzem db wkładka z mojego kodu. Czy możesz zaproponować coś, jak to osiągnąć w 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)' 

Opierając się na odpowiedź Lynn, w przypadku jesteś zbyt leniwy, aby wykonaj to w więcej niż jednym kroku - powinno to działać na wszystkich tabelach, w których znajduje się kolumna tożsamości.

Zastrzeżenie jest testowany tylko w 2012 i sp_MSforeachtable jest oczywiście całkowicie nieobsługiwanym ...

+0

Działa również na serwerze Sql Server 2014 i 2016 –

1

Opierając się na odpowiedź użytkownika @ KevD - To działa dobrze dla wyłączenia, ale tutaj jest bardziej dla umożliwiając również.

Aby wyłączyć wszystkie wkładki tożsamości, gdzie muszą być wyłączone, zastosowanie -

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

Aby włączyć wszystkie wkładki tożsamości, gdzie muszą być włączone, zastosowanie -

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

Testowane na serwerze SQL 2014 i 2016

0

Miałem podobny problem, ale wolałbym nie używać nieudokumentowanych procedur przechowywanych w produkcji. Aby zautomatyzować to, wbudowałem odpowiedź @Johna Deweya i umieściłem ją w kursorze. Powtarza to ponad 699 tabel w 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 

Jeśli grasz przeciwko kursorom, możesz łatwo przekształcić je w pętlę while.

Powiązane problemy