Отложенные ограничения в SQL Server - PullRequest
33 голосов
/ 16 июня 2009

Поддерживают ли какие-либо версии SQL Server отложенные ограничения (DC)?

Начиная с версии 8.0, Oracle поддерживает отложенные ограничения - ограничения, которые оцениваются только при фиксации группы операторов, а не при вставке или обновлении отдельных таблиц. Отложенные ограничения отличаются от простого отключения / включения ограничений тем, что ограничения все еще активны - они просто оцениваются позже (когда пакет фиксируется).

Преимущество DC состоит в том, что они позволяют оценивать обновления, которые по отдельности будут незаконными, что в совокупности приведет к действительному конечному состоянию. Примером является создание циклических ссылок в таблице между двумя строками, где каждая строка требует значения для существования. Никакой отдельный оператор вставки не пройдет ограничение - но группа может.

Чтобы прояснить мою цель, я собираюсь перенести реализацию ORM в C # на SQLServer - к сожалению, реализация опирается на Oracle DC, чтобы избежать вычисления порядка вставки / обновления / удаления среди строк.

Ответы [ 7 ]

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

OT: ИМХО есть несколько вещей, которые SQL Server не поддерживает, но они имеют смысл в корпоративной среде:

  • Отложенные ограничения, как упомянуто здесь
  • МАРС: Почему вам нужно установить опцию для чего-то совершенно естественного?
  • Ограничения CASCADE DELETE: SQL Server допускает только один единственный путь каскадирования для данного ограничения CASCADE DELETE. Опять же, я не вижу причины, по которой его нельзя разрешить каскадировать при удалении по нескольким возможным путям: в конце, в момент, когда он действительно выполняется, всегда будет использоваться только один путь, так почему это ограничение?
  • Предотвращение параллельных транзакций в одном соединении ADO.NET.
  • Принудительное выполнение каждой команды, выполняемой для соединения, в котором есть транзакция, для выполнения в этой транзакции.
  • При создании индекса UNIQUE значение NULL обрабатывается так, как если бы оно было фактическим значением, и в индексе разрешалось появляться только один раз. Однако представление SQL о NULL как «неизвестном значении» указывает на то, что значения NULL полностью игнорируются при создании индекса ...

Все эти мелочи делают многие функции ссылочной целостности и транзакций, которые вы ожидаете от полноразмерной СУБД, почти бесполезными в SQL Server. Например, поскольку отложенные ограничения не поддерживаются, понятие «транзакция» как внешне непротиворечивой единицы работы частично отрицается, единственное жизнеспособное решение, за исключением некоторых грязных обходных путей, заключается в том, чтобы вообще не определять ограничения ссылочной целостности. Я ожидаю, что естественным поведением транзакции будет то, что вы можете работать внутри нее так, как вам нравится, и в порядке операций, и система будет следить за тем, чтобы она была согласованной во время ее совершения. Подобные проблемы возникают из-за ограничения, что ограничение ссылочной целостности с ON DELETE CASCADE может быть определено только таким образом, что только одно единственное ограничение может привести к каскадному удалению объекта. Это действительно не подходит для большинства реальных сценариев.

11 голосов
/ 16 июня 2009

Пока что SQL Server их не поддерживает. Какую проблему вы решаете?

3 голосов
/ 16 июня 2009

Похоже, проблема в том, что SQL не поддерживает то, что Date и Darwen называют «множественным назначением». Стандартный ответ SQL на это был «отложенные ограничения», которые SQL Server не поддерживает. Ограничение FK или CHECK для SQL Server можно пометить с помощью NOCHECK, но оно не совсем то же самое. Дополнительные сведения см. В MSDN: ALTER TABLE (Transact-SQL) .

.
3 голосов
/ 16 июня 2009

Видимо, нет.

Я нашел около пяти разных постов в блогах, в которых говорилось, что SQLServer (в разных версиях) не поддерживает отложенные ограничения.

С другой стороны, я также нашел сообщение, которое пытается имитировать эту функцию, используя "постоянные вычисляемые столбцы", (прокрутка до последней записи), но caveat emptor

2 голосов
/ 19 января 2017

Существует метод, позволяющий обойти принудительное применение отсроченных ограничений при определенных условиях (по состоянию на январь 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 завершает все манипуляции с данными перед проверкой ограничений.

1 голос
/ 02 мая 2011

Если у вас есть собственный уровень ORM, одним из решений вашей проблемы может быть отделение логики вашего уровня ORM от обновления объекта от обновления ссылки. Затем ваш ORM будет работать с транзакциями, основанными на изменениях на стороне клиента, в несколько этапов:

  1. Удалите все ссылки на внешние ключи, определенные вашим набором изменений как удаленные, то есть установите соответствующие столбцы внешнего ключа в NULL или, для отношений, использующих таблицы сопоставления, УДАЛИТЕ записи из таблиц сопоставления соответствующим образом.
  2. Удалить все объекты, определенные как "удаленные" вашими наборами изменений
  3. Создайте все новые объекты в вашем наборе изменений, но пока не устанавливайте столбцы внешнего ключа
  4. Обновлять все изменения "примитивного" значения на любых обновленных объектах в наборе изменений, т.е. не обновлять столбцы внешнего ключа
  5. Установить значения столбца внешнего ключа, как определено в вашем наборе изменений.
  6. Добавление сопоставлений таблицы сопоставления для сопоставления связей на основе таблицы
  7. Commit

Это должно решить вашу проблему, так как все объекты, на которые есть ссылки, существуют в любое время, когда установлено значение внешнего ключа ...

0 голосов
/ 03 апреля 2018

Вы можете использовать этот метод

ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint

ваше действие

ALTER TABLE your_table WITH CHECK CHECK CONSTRAINT ALL
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...