ALTER COLUMN NOT NULL в хранимой процедуре всегда выполняется не последовательно? - PullRequest
1 голос
/ 23 февраля 2020

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

Поэтому я запускаю ALTER TABLE, чтобы установить столбец Я хочу в качестве первичного ключа NOT NULL:

ALTER TABLE Live1.dbo.Orders 
    ALTER COLUMN OrderID varchar(10) NOT NULL;

Затем, через 45 минут, и я добавляю свой первичный ключ:

ALTER TABLE Live1.dbo.Orders 
    ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID)

Пока все отлично и замечательно.

До этого я пытаюсь автоматизировать эту долгую и утомительную операцию.

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

CREATE PROCEDURE dbo.AddPKey
AS
BEGIN
    SET NOCOUNT ON;

    ALTER TABLE Live1.dbo.Orders ALTER COLUMN OrderID varchar(10) NOT NULL;
    ALTER TABLE Live1.dbo.Orders ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID)
END
GO

Сбой через 1 секунду с сообщением об ошибке:

Невозможно определить ограничение PRIMARY KEY для столбца с нулевым значением в таблице «Заказы». [SQLSTATE 42000] (Ошибка 8111) Не удалось создать ограничение или индекс. Смотрите предыдущие ошибки. [SQLSTATE 42000] (Ошибка 1750). Шаг не выполнен.

Таким образом, он пытается установить ограничение первичного ключа до завершения предыдущего шага ALTER COLUMN. Должно пройти не менее 45 минут, прежде чем он попытается добавить ограничение первичного ключа, но он попытается сделать это сразу. Если я запускаю ALTER COLUMN вручную, он работает просто отлично.

Что дает? Я написал десятки хранимых процедур, и ни одна из них не ведет себя так?

Что я могу сделать, чтобы заставить его ждать? Я думал, что это то, что сделала точка с запятой в конце строки ALTER COLUMN?

ОБНОВЛЕНИЕ:

Большое спасибо π за проницательный ответ и разъяснение того, что на самом деле здесь происходит. Мой последний сохраненный pro c выглядит так:

DECLARE @DynamicSQL nvarchar(4000)
 ALTER TABLE Live1.dbo.Orders ALTER COLUMN OrderID varchar(10) NOT NULL;
SET @DynamicSQL = 'ALTER TABLE Live1.dbo.Orders
                     ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID);'
EXEC Live1.sys.sp_executesql @DynamicSQL

, который работает без ошибок:)

1 Ответ

1 голос
/ 23 февраля 2020

Это потому, что во время синтаксического анализа операторов, когда SQL Сервер анализирует второй оператор, столбец по-прежнему может иметь значение null.

Два варианта:

  • Запустить второй оператор в виде динамического c SQL запроса с использованием sp_executesql. Это создаст отдельный контекст, и когда этот запрос будет проанализирован, первый уже будет запущен.
  • Создайте хранимую процедуру для простого добавления первичного ключа. Выполните его вместо оператора прямого изменения / добавления.

PS: точка с запятой служит для разделения (или завершения, если хотите) операторов на уровне языка. У него нет функциональности во время выполнения.

...