Вдохновленный вопросом моделирования Django: Моделирование базы данных с множественными отношениями «многие ко многим» в Django . ДБ-дизайн это что-то вроде:
CREATE TABLE Book
( BookID INT NOT NULL
, BookTitle VARCHAR(200) NOT NULL
, PRIMARY KEY (BookID)
) ;
CREATE TABLE Tag
( TagID INT NOT NULL
, TagName VARCHAR(50) NOT NULL
, PRIMARY KEY (TagID)
) ;
CREATE TABLE BookTag
( BookID INT NOT NULL
, TagID INT NOT NULL
, PRIMARY KEY (BookID, TagID)
, FOREIGN KEY (BookID) REFERENCES Book (BookID)
, FOREIGN KEY (TagID) REFERENCES Tag (TagID)
) ;
CREATE TABLE Aspect
( AspectID INT NOT NULL
, AspectName VARCHAR(50) NOT NULL
, PRIMARY KEY (AspectID)
) ;
CREATE TABLE TagAspect
( TagID INT NOT NULL
, AspectID INT NOT NULL
, PRIMARY KEY (TagID, AspectID)
, FOREIGN KEY (TagID) REFERENCES Tag (TagID)
, FOREIGN KEY (AspectID) REFERENCES Aspect (AspectID)
) ;
и вопрос заключается в том, как определить BookAspectRating
таблицу и обеспечить ссылочную целостность, поэтому нельзя добавить оценку для (Book, Aspect)
недопустимой комбинации.
AFAIK, сложные CHECK
ограничения (или ASSERTIONS
), которые включают подзапросы и более одной таблицы, которые могли бы решить эту проблему, недоступны ни в одной СУБД.
Другая идея - использовать (псевдокод) представление:
CREATE VIEW BookAspect_view
AS
SELECT DISTINCT
bt.BookId
, ta.AspectId
FROM
BookTag AS bt
JOIN
Tag AS t ON t.TagID = bt.TagID
JOIN
TagAspect AS ta ON ta.TagID = bt.TagID
WITH PRIMARY KEY (BookId, AspectId) ;
и таблица, которая имеет внешний ключ для вышеуказанного представления:
CREATE TABLE BookAspectRating
( BookID INT NOT NULL
, AspectID INT NOT NULL
, PersonID INT NOT NULL
, Rating INT NOT NULL
, PRIMARY KEY (BookID, AspectID, PersonID)
, FOREIGN KEY (PersonID) REFERENCES Person (PersonID)
, FOREIGN KEY (BookID, AspectID)
REFERENCES BookAspect_view (BookID, AspectID)
) ;
Три вопроса:
Существуют ли СУБД, допускающие (возможно, материализованные)
VIEW
сPRIMARY KEY
?Существуют ли СУБД , которые позволяют ,
FOREIGN KEY
чтоREFERENCES
вVIEW
(а не только базыTABLE
)?Может ли эта проблема целостности быть решена иначе - с помощью доступных функций СУБД?
Разъяснение:
Поскольку, вероятно, нет 100% удовлетворительного решения - и вопрос Джанго даже не мой! - Меня больше интересует общая стратегия возможной атаки на проблему, а не детальное решение. Таким образом, ответ типа «в СУБД-Х это можно сделать с помощью триггеров в таблице А» вполне приемлем.
источник
Ответы:
Это бизнес-правило может быть применено в модели с использованием только ограничений. Следующая таблица должна решить вашу проблему. Используйте это вместо своего представления:
источник
TagID
другой тег, связанный с той же комбинацией BookAspect.Я думаю, вы обнаружите, что во многих случаях сложные бизнес-правила не могут быть реализованы с помощью одной модели. Это один из тех случаев, когда, по крайней мере в SQL Server, я думаю, что триггер (предпочтительно вместо триггера) лучше подходит для вашей цели.
источник
В Oracle одним из способов принудительного применения такого рода ограничений декларативным способом было бы создание материализованного представления, настроенного на быстрое обновление при коммите, запрос которого идентифицирует все недопустимые строки (т.
BookAspectRating
Е. Строки, в которых нет совпаденийBookAspect_view
). Затем вы можете создать тривиальное ограничение для этого материализованного представления, которое будет нарушено, если в материализованном представлении есть какие-либо строки. Это позволяет минимизировать объем данных, которые необходимо дублировать в материализованном представлении. Однако это может вызвать проблемы, поскольку ограничение применяется только в тот момент, когда вы фиксируете транзакцию - многие приложения не написаны так, чтобы ожидать, что операция фиксации может завершиться неудачей, - и потому что нарушение ограничения может быть довольно сложным связать с определенной строкой или конкретной таблицей.источник
SIRA_PRISE позволяет это.
Хотя FK больше не называется «FK», а просто «ограничением базы данных», и «представление» фактически даже не нужно определять как представление, вы можете просто включить выражение, определяющее выражение, в объявление ограничение базы данных.
Ваше ограничение будет выглядеть примерно так
и вы сделали.
Однако в большинстве СУБД SQL вам придется выполнить анализ вашего ограничения, определить, как оно может быть нарушено, и реализовать все необходимые триггеры.
источник
В PostgreSQL я не могу представить решение без привлечения триггеров, но оно, безусловно, может быть решено таким образом (будь то поддержание какого-либо материализованного представления или включение до запуска
BookAspectRating
). Нет внешних ключей, ссылающихся на view (ERROR: referenced relation "v_munkalap" is not a table
), не говоря уже о первичном ключе.источник