Я пытаюсь обновить базу данных, которая поддерживается и развертывается с помощью проекта базы данных (.sqlproj
) в Visual Studio 2012. Это проще с SQL Server Management Studio, но в этом случае мне нужно развернуть с помощью DACPAC.
Как правильно изменить столбец, чтобы он не допускал значения NULL, с помощью DACPAC и без риска потери данных?
В таблицу был добавлен столбец, допускающий значение NULL. Теперь мне нужно опубликовать обновление, которое устанавливает значение столбца не равным нулю и задает значение по умолчанию. Поскольку в таблице есть строки, обновление не выполняется. Есть параметр «разрешить потерю данных», но это не вариант для нас, и это обновление не должно приводить к потере данных. Вот простой пример, показывающий проблему:
CREATE TABLE [dbo].[Hello]
(
[Id] INT IDENTITY(100,1) NOT NULL PRIMARY KEY,
[HelloString] NVARCHAR(50) NULL ,
[Language] NCHAR(2) NOT NULL
)
Теперь опубликуйте эту базу данных и добавьте строки, по крайней мере, одна строка должна иметь значение null для HelloString.
Измените определение таблицы на:
CREATE TABLE [dbo].[Hello]
(
[Id] INT IDENTITY(100,1) NOT NULL PRIMARY KEY,
[HelloString] NVARCHAR(50) NOT NULL DEFAULT 'Hello' ,
[Language] NCHAR(2) NOT NULL
)
Это не может быть опубликовано.
Ошибка:
Обнаружены строки. Обновление схемы прекращается, поскольку может произойти потеря данных.
Затем я попытался добавить сценарий перед развертыванием, чтобы установить для всех NULL значение «Hello»:
UPDATE Hello SET HelloString = 'Hello' WHERE HelloString IS NULL
Эта попытка публикации также не удалась с той же ошибкой. Глядя на автоматически созданный скрипт публикации, становится ясно, почему, но это кажется неправильным поведением.
- Изменение
NOT NULL
применяется ДО добавления значения по умолчанию - Скрипт проверяет наличие ЛЮБЫХ строк, неважно, есть там нули или нет.
Совет в комментарии (чтобы избежать этой проблемы, вы должны добавить значения в этот столбец для всех строк) не решает эту проблему.
/*
The column HelloString on table [dbo].[Hello] must be changed from NULL to NOT NULL. If the table contains data, the ALTER script may not work. To avoid this issue, you must add values to this column for all rows or mark it as allowing NULL values, or enable the generation of smart-defaults as a deployment option.
*/
IF EXISTS (select top 1 1 from [dbo].[Hello])
RAISERROR (N'Rows were detected. The schema update is terminating because data loss might occur.', 16, 127) WITH NOWAIT
GO
PRINT N'Altering [dbo].[Hello]...';
GO
ALTER TABLE [dbo].[Hello] ALTER COLUMN [HelloString] NVARCHAR (50) NOT NULL;
GO
PRINT N'Creating Default Constraint on [dbo].[Hello]....';
GO
ALTER TABLE [dbo].[Hello]
ADD DEFAULT 'hello' FOR [HelloString];
Встречается в SQL Server 2012 (v11.0.5343), SQL Server Data Tools 11.1.31009.1