Как я могу обновить столбец, допускающий значение NULL, чтобы он не допускал значения NULL, в SQL Server с помощью DACPAC

Я пытаюсь обновить базу данных, которая поддерживается и развертывается с помощью проекта базы данных (.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

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

  1. Изменение NOT NULL применяется ДО добавления значения по умолчанию
  2. Скрипт проверяет наличие ЛЮБЫХ строк, неважно, есть там нули или нет.

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

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


person mafue    schedule 19.08.2015    source источник
comment
Можете ли вы вставить значение по умолчанию в пустые поля, а затем выполнить обновление?   -  person Holmes IV    schedule 19.08.2015
comment
@HolmesIV Я пытаюсь сделать это с помощью сценария перед развертыванием, но я попытаюсь выполнить его отдельно, чтобы посмотреть, имеет ли это значение. Спасибо!   -  person mafue    schedule 19.08.2015


Ответы (1)


При публикации dacpac с использованием SSMS у вас не будет доступа к полному набору параметров публикации, которые доступны при публикации из SqlPackage.exe или Visual Studio. Я бы посоветовал опубликовать с помощью SqlPackage.exe или Visual Studio и включить параметр «Создавать интеллектуальные значения по умолчанию, где это применимо». В случае SqlPackage.exe вы должны запустить такую ​​команду, как:

"C:\Program Files (x86)\Microsoft SQL Server\120\DAC\bin\SqlPackage.exe" /a:publish /sf:"C:\MyDacpac.dacpac" /tcs:"Data Source=MYSERVER;Initial Catalog=MYDATABASE;Integrated Security=true" /p:GenerateSmartDefaults=true

В случае Visual Studio вы должны установить флажок «Создать интеллектуальные значения по умолчанию» в диалоговом окне «Дополнительные параметры публикации».

person Steven Green    schedule 19.08.2015
comment
«Создать интеллектуальные значения по умолчанию» используется для создания значений по умолчанию для столбца, для которого не определено значение по умолчанию. Здесь дело обстоит не так, я определил значение по умолчанию для своего столбца. Но глядя на автогенерированный SQL, я вижу, что он пытается применить мое значение по умолчанию после изменения значения столбца def на NOT NULL, так что, возможно, ваш ответ - обходной путь. Вы это имели в виду? - person mafue; 20.08.2015
comment
да. Вы на правильном пути, используя сценарий перед развертыванием для замены нулевых значений желаемым значением. Сочетание этого с включенной настройкой генерации интеллектуальных значений по умолчанию позволит вам успешно выполнить развертывание. Есть альтернатива этому, но для этого нужно написать Участник развертывания, что дает больше работы. - person Steven Green; 20.08.2015
comment
Это работает. Он делает то же самое, что и мой сценарий перед развертыванием, но также (что наиболее важно) удаляет плохую строку из сценария autogen'd, который выдает, если есть какие-либо строки (с нулями или без). - person mafue; 21.08.2015