2012-04-04 6 views
11

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

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

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

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

ответ

16

Это было cross posted on Database Administrators, поэтому я мог бы также опубликовать свой ответ оттуда здесь, чтобы помочь будущим искателям.

Это может быть сделано как изменение только метаданных (т.е. без переноса всех данных в новую таблицу) с использованием 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; 

ВНИМАНИЕ: если ваша таблица содержит столбец IDENTITY вам нужно переустановку значение IDENTITY. SWITCH TO сбрасывает семя столбца идентификации, и если у вас нет ограничения UNIQUE или PRIMARY KEY для идентификации (например, при использовании индекса CLUSTERED COLUMNSTORE в SQL 2014), вы не заметите его сразу. Для правильной установки начального значения необходимо использовать DBCC CHECKIDENT ('dbo.YourTable', RESEED, [reseed value]).

+0

Сохраняет ли это все индексы и ограничения исходной таблицы? –

+0

Нет, он не сохранит все индексы и ограничения. – xav

+0

@xav это будет, если вы включите их в 'create table'. –

2

К сожалению, нет способа, как это сделать без воссоздания. Вам нужно создать новую таблицу с 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 их ручной.

+0

У нас есть представление, связанное с этой таблицей. Итак, каков наилучший способ переноса данных из этой таблицы в новую созданную таблицу без влияния на представления и связанные таблицы? –

+0

Да, мы создали представления с параметром schemabinding. Можем ли мы изменить представление для удаления schemabinding, а затем запустить ваш запрос. Является ли это возможным? –

+0

Отражены ли ваши взгляды? В чем причина их превращения в схему? –

0

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

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

  1. Создание снимка базы данных для базы данных, которая содержит таблицу
  2. Script определение таблицы из таблицы, которую вы собираетесь обновить
  3. Удалить таблицу, вы собираетесь для обновления (убедитесь, что моментальный снимок базы данных успешно создан)
  4. Обновить SET ANSI NULL с OFF до 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. Migrate не кластерный индекс вручную (получить скрипт из моментального снимка базы данных)

Использование выше:

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^