2012-04-04 16 views
11

W naszej bazie danych znajduje się tabela utworzona z ANSI_NULLS OFF. Teraz stworzyliśmy widok przy użyciu tej tabeli. I chcemy dodać indeks klastrowany dla tego widoku.Zaktualizuj opcję ANSI_NULLS w istniejącej tabeli

Podczas tworzenia indeksu klastrowanego wyświetlany jest błąd, taki jak nie można utworzyć indeksu, ponieważ ANSI_NULL jest wyłączona dla tej konkretnej tabeli.

Ta tabela zawiera dużą ilość danych. Dlatego chcę zmienić tę opcję na WŁĄCZENIA bez utraty danych.

Czy istnieje sposób zmiany tabeli w celu zmodyfikowania tej opcji. Proszę podać swoje sugestie.

Odpowiedz

16

To był cross posted on Database Administrators, więc równie dobrze mogę opublikować moją odpowiedź tutaj, aby pomóc przyszłym użytkownikom.

Można to zrobić jako zmianę tylko metadanych (tj. Bez przeniesienia wszystkich danych do nowej tabeli) przy użyciu ALTER TABLE ... SWITCH.

Przykładowy kod poniżej

/*Create table with option off*/ 
SET ANSI_NULLS OFF; 

CREATE TABLE dbo.YourTable (X INT) 

/*Add some data*/ 
INSERT INTO dbo.YourTable VALUES (1),(2),(3) 

/*Confirm the bit is set to 0*/ 
SELECT uses_ansi_nulls, * 
FROM sys.tables 
WHERE object_id = object_id('dbo.YourTable') 

GO 

BEGIN TRY 
    BEGIN TRANSACTION; 
    /*Create new table with identical structure but option on*/ 
    SET ANSI_NULLS ON; 
    CREATE TABLE dbo.YourTableNew (X INT) 

    /*Metadata only switch*/ 
    ALTER TABLE dbo.YourTable SWITCH TO dbo.YourTableNew; 

    DROP TABLE dbo.YourTable; 

    EXECUTE sp_rename N'dbo.YourTableNew', N'YourTable','OBJECT'; 

    /*Confirm the bit is set to 1*/ 
    SELECT uses_ansi_nulls, * 
    FROM sys.tables 
    WHERE object_id = object_id('dbo.YourTable') 

    /*Data still there!*/ 
    SELECT * 
    FROM dbo.YourTable 

    COMMIT TRANSACTION; 
END TRY 

BEGIN CATCH 
    IF XACT_STATE() <> 0 
     ROLLBACK TRANSACTION; 

    PRINT ERROR_MESSAGE(); 
END CATCH; 

UWAGA: gdy tabela zawiera kolumny tożsamości trzeba reseedować wartość tożsamości. Przełącznik TO spowoduje zresetowanie materiału siewnego kolumny tożsamości i jeśli nie masz ograniczenia UNIQUE lub PRIMARY KEY na tożsamości (np. Przy użyciu CLUMEROWANEGO indeksu COLUMNSTORE w SQL 2014), nie zauważysz tego od razu. Należy użyć DBCC CHECKIDENT ("dbo.YourTable", RESEED, [reseed value]), aby poprawnie ustawić wartość początkową ponownie.

+0

Czy zachowają one wszystkie indeksy i ograniczenia oryginalnego stołu? –

+0

Nie będzie zachowywał wszystkich indeksów i ograniczeń. – xav

+0

@xav to zrobi, jeśli umieścisz je w 'create table'. –

2

Niestety, nie ma sposobu, aby to zrobić bez odtwarzania. Musisz utworzyć nową tabelę pod numerem ANSI_NULLS ON i skopiować tam wszystkie dane.

Powinno być coś takiego:

SET ANSI_NULLS ON; 

CREATE TABLE new_MyTBL (
.... 
) 

-- stop all processes changing your data at this point 

SET IDENTITY_INSERT new_MyTBL ON 

INSERT new_MyTBL (...) -- including IDENTITY field 
SELECT ...    -- including IDENTITY field 
FROM MyTBL 

SET IDENTITY_INSERT new_MyTBL OFF 

-- alter/drop WITH SCHEMABINDING objects at this point 

EXEC sp_rename @objname = 'MyTBL', @newname = 'old_MyTBL' 
EXEC sp_rename @objname = 'new_MyTBL', @newname = 'MyTBL' 

-- alter/create WITH SCHEMABINDING objects at this point 
-- re-enable your processes 

DROP TABLE old_MyTBL  -- do that when you are sure that system works OK 

Jeśli są jakieś zależności obiektów, będą pracować z nowej tabeli tak szybko, jak ją zmienić. Ale jeśli niektóre z nich są WITH SCHEMABINDING, musisz je wykonać ręcznie: DROP i CREATE.

+0

Mamy widok skojarzony z tym stołem. Jaka jest najlepsza metoda migracji danych z tej tabeli do nowo utworzonej tabeli bez wpływu na widoki i powiązane tabele? –

+0

Tak, stworzyliśmy widoki z opcją schemabinding. Czy możemy zmienić widok, aby usunąć schematobinding, a następnie uruchomić zapytanie. Czy to możliwe? –

+0

Czy Twoje poglądy są indeksowane? Jaki był powód, by je przeprogramowywać? –

0

Spróbowałem opcji SWITCH zalecanej powyżej, ale nie udało mi się RESEED tożsamości. Nie mogłem się dowiedzieć dlaczego.

użyłem następujące alternatywne podejście zamiast:

  1. Utwórz migawkę bazy danych do bazy danych zawierający tabelę
  2. Script definicję tabeli tabeli, którą zamierzasz aktualizować
  3. Usuń tabelę, które zamierzają Aby zaktualizować (upewnij się, że migawka bazy danych została pomyślnie utworzona)
  4. Zaktualizuj zestaw ANSI NULL od OFF do ON ze skryptu uzyskanego w kroku 2 i uruchom zaktualizowany skrypt. Tabela została odtworzona.
  5. dane zapełnić z migawka bazy danych do tabeli: SET IDENTITY_INSERT TABLE_NAME ON INSERT INTO TABLE_NAME (PK, col1, etc.) SELECT PK, col1, etc. FROM [Database_Snapshot].dbo.TABLE_NAME SET IDENTITY_INSERT TABLE_NAME OFF
  6. Migrate non indeksu klastrowego ręcznie (pobierz skrypt z migawka bazy danych)

Korzystanie z powyższym:

  • ja nie musiał martwić się o ograniczenia i klucze, ponieważ nazwy tabeli/ograniczeń zawsze pozostają takie same (nie muszę zmieniać nazwy)
  • Mam kopię zapasową moich danych (migawka), na których mogę polegać, aby dokładnie sprawdzić, czy niczego nie brakuje.
  • I nie trzeba reseedować tożsamości

Rozumiem usuwanie tabeli nie zawsze może być proste, jeśli stół jest wymieniony w innych tabelach. W tym przypadku tak nie było. Miałem szczęście.

Powiązane problemy