Противоречат требования внешнего ключа CASCADE и RESTRICT?

StackOverflow https://stackoverflow.com/questions/353804

Вопрос

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

Теперь у меня есть дополнительная таблица ЗАВИСИМОСТИ.Каждая запись в таблице зависимостей представляет собой два файла, что указывает на то, что первый файл зависит от второго.Опять же, это внешние ключи, для первого установлено значение CASCADE (поэтому, если я удалю запись файла, эта запись будет удалена), а для второго установлено значение RESTRICT (поэтому мне не разрешено удалять запись файла, если какие-либо другие файлы зависят от в теме).Опять вроде все хорошо.

К сожалению, похоже, я больше не могу удалить проект с помощью одного оператора удаления SQL!При удалении предпринимается попытка каскадного удаления файлов, но если какой-либо из них появляется в таблице DEPENDENCIES, внешний ключ RESTRICT предотвращает удаление (даже если эта запись в таблице зависимостей будет удалена, поскольку другой столбец — CASCADE).Единственный обходной путь, который у меня есть, — это рассчитать точный порядок удаления файлов, чтобы не было нарушено ни одно из ограничений записей зависимостей, и удалять записи файлов по одной, прежде чем пытаться удалить проект.

Есть ли способ настроить мою схему базы данных так, чтобы одно удаление SQL из таблицы проектов правильно каскадировало другие удаления?Я использую Firebird 2.1, но не знаю, имеет ли это какое-то значение - кажется, должен быть способ заставить это работать?

Это было полезно?

Решение

Вы не можете контролировать порядок удаления с помощью каскадного внешнего ключа, но вы можете создать триггер для PROJECTS удалить строки в FILES которые принадлежат этому проекту и также перечислены в DEPENDENCIES как зависимый от других FILES.Сделайте это BEFORE DELETE триггер, поэтому он должен выполняться до каскадных эффектов.

Что-то вроде этого:

CREATE TRIGGER Del_Child_Files FOR PROJECTS
BEFORE INSERT
AS BEGIN
  FOR SELECT F.FILE_ID FROM FILES F JOIN DEPENDENCIES D 
      ON F.FILE_ID = D.CHILD_ID
    WHERE F.PROJECT_ID = OLD.PROJECT_ID
    INTO :file_id
  DO
    DELETE FROM FILES WHERE FILE_ID = :file_id;
  DONE
END

Поэтому, когда вы удаляете проект, удаляются все «дочерние» файлы проекта, которые зависят от других файлов, и это приводит к каскадному удалению строк в DEPENDENCIES поэтому все оставшиеся файлы свободны от зависимостей.Удаление проекта теперь может каскадно удалять эти файлы.

Я не проверял это, и мой синтаксис Firebird может быть устаревшим, но, возможно, он поможет вам начать.

Очевидно, пожалуйста, протестируйте это на копии ваших данных, а не на реальных данных!

Другие советы

Поддерживает ли система отложенные ограничения, при которых проверку ограничений можно отложить до момента фиксации?

Хотя, возможно, это просто особенность Oracle.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top