2015-08-19 6 views
6

Я пытаюсь обновить базу данных, которая поддерживается и развертывается с использованием проекта базы данных (.sqlproj) в Visual Studio 2012. Это проще с SQL Server Management Studio, но в этом случае я должен использовать DACPAC.Как обновить столбец с нулевым значением, который не может быть нулевым, в SQL Server с использованием DACPAC

Каков правильный способ изменения столбца, чтобы он не мог быть нулевым, с использованием DACPAC и без риска потери данных?

В таблицу была добавлена ​​нулевая колонка. Теперь мне нужно опубликовать обновление, которое устанавливает столбец не null и устанавливает значение по умолчанию. Поскольку в таблице есть строки, обновление не выполняется. Существует параметр «разрешить потерю данных», но это не вариант для нас, и это обновление не должно приводить к потере данных. Вот простой пример, который показывает проблему:

CREATE TABLE [dbo].[Hello] 
(
    [Id] INT IDENTITY(100,1) NOT NULL PRIMARY KEY, 
    [HelloString] NVARCHAR(50) NULL , 
    [Language] NCHAR(2) NOT 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 
) 

Это не может быть опубликована.

Ошибка:

Rows were detected. The schema update is terminating because data loss might occur.

Далее я пытался добавить сценарий предварительного развертывания, чтобы установить все 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 11.1.31009.1

+0

Можете ли вы вставить значение по умолчанию в нулевые поля, а затем выполнить обновление? –

+0

@HolmesIV Я пытаюсь сделать это с помощью сценария предварительного развертывания, но я попытаюсь выполнить его отдельно, чтобы узнать, имеет ли это значение. Благодаря! – mafue

ответ

3

При публикации 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, вы бы проверить Формировать вариант смарт настройки по умолчанию в Advanced публиковать диалог опций.

+0

«Сгенерировать интеллектуальные значения по умолчанию» используется для генерации значений по умолчанию для столбца, который по умолчанию не задан. Это не тот случай, я определил значение по умолчанию для своего столбца. Но, глядя на autogen'd SQL, я вижу, что он пытается применить мой дефолт после изменения столбца def до NOT NULL, так что, возможно, ваш ответ является обходным путем. Это ты имел в виду? – mafue

+0

Да. Вы находитесь на правильном пути, используя сценарий предварительного развертывания, чтобы заменить нулевые значения на нужное значение. Объединяя это с включенным параметром «generate smart defaults», вы сможете успешно развернуться. Существует альтернатива этому, но он включает в себя запись [Участник развертывания] (https://msdn.microsoft.com/en-US/library/dn306642 (v = vs.103) .aspx), что больше работает. –

+0

Это работает. Он делает то же самое, что и мой сценарий предварительного развертывания, но он также (самое главное) удаляет плохую строку из сценария autogen'd, который выдает, если есть какие-либо строки (с нулями или без них). – mafue