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