Существует метод, позволяющий обойти принудительное применение отсроченных ограничений при определенных условиях (по состоянию на январь 2017 года в SQL Server поддержка отложенных ограничений отсутствует). Рассмотрим следующую схему базы данных:
Отказ от ответственности: качество схемы или варианта использования здесь не подлежит обсуждению, оно приводится в качестве основного примера для обходного пути
CREATE TABLE T (Id TYPE NOT NULL PRIMARY KEY, NextId TYPE NOT NULL);
ALTER TABLE T WITH CHECK ADD CONSTRAINT FK_T2T
FOREIGN KEY (NextId) REFERENCES T (Id);
CREATE UNIQUE NONCLUSTERED INDEX UC_T ON T (NextId);
Где TYPE - некоторый подходящий тип данных для суррогатного ключа. Предполагается, что значение для суррогатного ключа присваивается СУБД во время операции INSERT (т. Е. IDENTITY).
Вариант использования: сохранить «последнюю» версию сущности T с NextId = NULL и сохранить предыдущие версии, поддерживая односвязный список T.NextId -> T.Id.
Очевидно, что данная схема подвержена проблеме отложенного ограничения, потому что вставка новой «последней» версии должна предшествовать обновлению старой «последней», и в течение этого времени в базе данных будет две записи с то же значение NextId.
Теперь, если:
Тип данных первичного ключа не должен быть числовым, и его можно рассчитать заранее (т. Е. UNIQUEIDENTIFIER), тогда проблема отложенного ограничения обходится с помощью инструкции MERGE, например:
DECLARE @MergeTable TABLE (Id UNIQUEIDENTIFIER);
DECLARE @NewLatestVersion UNIQUEIDENTIFIER = NEWID();
INSERT INTO @MergeTable (Id) VALUES (@NewLatestVersion);
INSERT INTO @MergeTable (Id) VALUES (@OldLatestVersion);
MERGE INTO T
USING @MergeTable m ON T.Id = m.Id
WHEN MATCHED THEN UPDATE SET T.NextId = @NewLatestVersion
WHEN NOT MATCHED THEN INSERT (Id) VALUES (@NewLatestVersion);
По-видимому, оператор MERGE завершает все манипуляции с данными перед проверкой ограничений.