Inspirado por uma pergunta de modelagem do Django: Modelagem de Banco de Dados com várias relações muitos-para-muitos no Django . O design do db é algo como:
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)
) ;
e o problema é como definir a BookAspectRating
tabela e impor a integridade referencial; portanto, não é possível adicionar uma classificação para uma (Book, Aspect)
combinação inválida.
AFAIK, CHECK
restrições complexas (ou ASSERTIONS
) que envolvem subconsultas e mais de uma tabela, que poderia resolver isso, não estão disponíveis em nenhum DBMS.
Outra idéia é usar (pseudocódigo) uma visão:
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) ;
e uma tabela que possui uma chave estrangeira para a exibição acima:
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)
) ;
Três perguntas:
Existem DBMS que permitem um (possivelmente materializado)
VIEW
com umPRIMARY KEY
?Existem DBMS que permitem que um
FOREIGN KEY
queREFERENCES
umVIEW
(e não apenas uma baseTABLE
)?Esse problema de integridade poderia ser resolvido de outra forma - com os recursos DBMS disponíveis?
Esclarecimento:
Como provavelmente não existe uma solução 100% satisfatória - e a questão do Django nem sequer é minha! - Estou mais interessado em uma estratégia geral de possível ataque ao problema, não em uma solução detalhada. Portanto, uma resposta como "no DBMS-X isso pode ser feito com gatilhos na tabela A" é perfeitamente aceitável.