Отложенные ограничения в SQL Server
Поддерживают ли какие-либо версии SQL Server отложенные ограничения (DC)?
Начиная с версии 8.0, Oracle поддерживает отложенные ограничения - ограничения, которые оцениваются только при фиксации группы операторов, а не при вставке или обновлении отдельных таблиц. Отложенные ограничения отличаются от простого отключения / включения ограничений тем, что ограничения все еще активны - они просто оцениваются позже (когда пакет зафиксирован).
Преимущество DC состоит в том, что они позволяют оценивать обновления, которые по отдельности были бы незаконными, и в совокупности приводили к действительному конечному состоянию. Примером является создание циклических ссылок в таблице между двумя строками, где каждая строка требует значения для существования. Никакой отдельный оператор вставки не пройдет ограничение - но группа может.
Чтобы прояснить мою цель, я хочу перенести реализацию ORM в C# на SQLServer - к сожалению, реализация опирается на Oracle DC, чтобы избежать вычисления порядка вставки / обновления / удаления между строками.
7 ответов
Пока что SQL Server их не поддерживает. Какую проблему вы решаете?
OT: ИМХО есть несколько вещей, которые SQL Server не поддерживает, но они имеют смысл в корпоративной среде:
- Отложенные ограничения, как упомянуто здесь
- МАРС: Почему вам нужно установить опцию для чего-то совершенно естественного?
- Ограничения CASCADE DELETE: SQL Server допускает только один единственный путь каскадирования для данного ограничения CASCADE DELETE. Опять же, я не вижу причины, по которой его нельзя разрешить каскадировать при удалении по нескольким возможным путям: в конце, в момент, когда он действительно выполняется, всегда будет использоваться только один путь, так почему это ограничение?
- Предотвращение параллельных транзакций на одном соединении ADO.NET.
- Принудительное выполнение каждой команды, выполняемой в соединении, в котором есть транзакция, для выполнения в этой транзакции.
- При создании индекса UNIQUE значение NULL обрабатывается так, как если бы оно было фактическим значением, и в индексе разрешалось появляться только один раз. Однако представление SQL о NULL как "неизвестном значении" указывает на то, что значения NULL полностью игнорируются при создании индекса...
Все эти мелочи делают многие функции ссылочной целостности и транзакций, которые вы ожидаете от полноразмерной СУБД, практически бесполезными в SQL Server. Например, поскольку отложенные ограничения не поддерживаются, понятие "транзакция" как внешне непротиворечивой единицы работы частично отрицается, единственное жизнеспособное решение, за исключением некоторых грязных обходных путей, заключается в том, чтобы вообще не определять ограничения ссылочной целостности. Я ожидаю, что естественным поведением транзакции будет то, что вы можете работать внутри нее так, как вам нравится, и в порядке операций, и система будет следить за тем, чтобы она была согласованной во время ее совершения. Подобные проблемы возникают из-за ограничения, что ограничение ссылочной целостности с ON DELETE CASCADE может быть определено только таким образом, что только одно единственное ограничение может привести к каскадному удалению объекта. Это действительно не подходит для большинства реальных сценариев.
Похоже, проблема в том, что SQL не поддерживает то, что Date и Darwen называют "множественным назначением". Ответ Standard SQL на это был "отложенные ограничения", которые SQL Server не поддерживает. Ограничение FK или CHECK для SQL Server можно пометить с помощью NOCHECK, но оно не совсем то же самое. Для получения дополнительной информации см. MSDN: ALTER TABLE (Transact-SQL).
Очевидно нет.
Я нашел около пяти разных постов в блогах, в которых говорилось, что SQLServer (в разных версиях) не поддерживает отложенные ограничения.
С другой стороны, я также нашел сообщение, которое пытается имитировать эту функцию с помощью "сохраняемых вычисляемых столбцов" (прокрутка до последней записи), но с оговоркой emptor
Если у вас есть свой собственный уровень ORM, одним из решений вашей проблемы может быть разделение обновления объекта и обновления ссылки с помощью логики вашего уровня ORM. Затем ваш ORM будет работать с транзакциями, основанными на изменениях на стороне клиента, в несколько этапов:
- Удалите все ссылки на внешние ключи, определенные вашим набором изменений как удаленные, т. Е. Установите соответствующие столбцы внешнего ключа в NULL, или, для отношений, использующих таблицы сопоставления, УДАЛИТЕ записи из таблиц сопоставления соответствующим образом.
- Удалить все объекты, определенные как "удаленные" вашими наборами изменений
- Создайте все новые объекты в вашем наборе изменений, но пока не устанавливайте столбцы внешнего ключа
- Обновите все изменения "примитивного" значения на любых обновленных объектах в наборе изменений, т.е. не обновляйте столбцы внешнего ключа
- Установите значения столбца внешнего ключа, как определено в вашем наборе изменений.
- Добавить сопоставления таблицы сопоставления для сопоставления связей на основе таблицы
- совершить
Это должно решить вашу проблему, так как все объекты, на которые есть ссылки, существуют в любое время, когда установлено значение внешнего ключа...
Есть способ обойти пропущенное принудительное применение ограничений при определенных условиях (по состоянию на январь 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 TABLE @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 завершает все манипуляции с данными перед проверкой ограничений.
Вы можете использовать этот метод
ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint
ваше действие
ALTER TABLE your_table WITH CHECK CHECK CONSTRAINT ALL