Противоречивые требования к внешнему ключу CASCADE и RESTRICT? - PullRequest
2 голосов
/ 09 декабря 2008

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

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

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

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

Ответы [ 2 ]

4 голосов
/ 09 декабря 2008

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

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

0 голосов
/ 09 декабря 2008

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

Может быть, это просто вещь Оракула. ​​

...