Обновить параметр ANSI NULLS в существующей таблице

в нашей базе данных есть таблица, которая создается с ANSI_NULLS OFF. Теперь мы создали представление, используя эту таблицу. И мы хотим добавить кластеризованный индекс для этого представления.

при создании кластеризованного индекса он показывает ошибку, как не может создать индекс, так как ANSI_NULL выключен для этой конкретной таблицы.

эта таблица содержит большой объем данных. Поэтому я хочу изменить этот параметр без потери данных.

есть ли способ, чтобы изменить таблица для изменения этой опции . Пожалуйста, дайте свои предложения.

3 ответов


Это крест размещен на администраторах баз данных поэтому я мог бы также опубликовать свой ответ оттуда здесь, чтобы помочь будущим искателям.

Это можно сделать только как изменение метаданных (т. е. без переноса всех данных в новую таблицу) с помощью ALTER TABLE ... SWITCH.

пример кода ниже

/*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; 

предупреждение: если таблица содержит столбец идентификатора, необходимо повторно заполнить значение идентификатора. Переключатель TO сбросит начальное значение столбца identity и если у вас нет ограничения уникального или первичного ключа для идентификатора (например, при использовании кластеризованного индекса COLUMNSTORE в SQL 2014), вы его сразу не заметите. Вам нужно использовать DBCC CHECKIDENT ('dbo.YourTable', RESEED, [reseed value]), чтобы правильно установить значение семени снова.


к сожалению, нет способа сделать это без воссоздания. Вам нужно создать новую таблицу с ANSI_NULLS ON и скопировать туда все данные.

Это должно быть что-то вроде:

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

если есть какие-либо зависимые объекты, они будут работать с новой таблицей, как только вы переименуете ее. Но если некоторые из них WITH SCHEMABINDING вам нужно DROP и CREATE их в ручную.


я попробовал параметр коммутатора, рекомендованный выше, но не смог переустановить идентификатор. Я не мог понять почему.

вместо этого я использовал следующий альтернативный подход:

  1. создать моментальный снимок базы данных для базы данных, содержащей таблицу
  2. определение таблицы скриптов таблицы, которую вы собираетесь обновить
  3. удалите таблицу, которую вы собираетесь обновить (убедитесь, что снимок базы данных успешно создан)
  4. набор обновлений ANSI NULLs from OFF to ON из скрипта, полученного с шага 2, и запуск обновленного скрипта. Таблица теперь воссоздана.
  5. заполнение данных из моментального снимка базы данных в таблицу: 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. перенос некластеризованного индекса вручную (получить скрипт из моментального снимка базы данных)

используя вышеуказанные:

  • мне не пришлось беспокоиться об ограничениях и ключах, так как имена таблиц/ограничений всегда остаются неизменными (мне не нужно переименовывать что угодно)
  • у меня есть резервная копия моих данных (снимков), что я могу положиться, чтобы проверить, что ничего не пропало.
  • мне не нужно повторно устанавливать личность

Я понимаю, что удаление таблицы не всегда может быть простым, если таблица упоминается в других таблицах. В данном случае это было не так.. Мне повезло.