Inspirado en una pregunta de modelado de Django: modelado de bases de datos con múltiples relaciones de muchos a muchos en Django . El diseño db es algo así 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)
) ;
y el problema es cómo definir la BookAspectRating
tabla y hacer cumplir la integridad referencial, por lo que no se puede agregar una calificación para una (Book, Aspect)
combinación que no es válida.
AFAIK, las CHECK
restricciones complejas (o ASSERTIONS
) que involucran subconsultas y más de una tabla, que posiblemente podrían resolver esto, no están disponibles en ningún DBMS.
Otra idea es usar (pseudocódigo) una vista:
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) ;
y una tabla que tiene una clave externa para la vista anterior:
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)
) ;
Tres preguntas:
¿Hay DBMS que permiten un (posiblemente materializado)
VIEW
con unPRIMARY KEY
?¿Hay DBMS que permiten
FOREIGN KEY
queREFERENCES
aVIEW
(y no solo una baseTABLE
)?¿Podría resolverse este problema de integridad de otra manera, con las funciones DBMS disponibles?
Aclaración:
Dado que probablemente no haya una solución 100% satisfactoria, ¡y la pregunta de Django ni siquiera es mía! - Estoy más interesado en una estrategia general de posible ataque al problema, no en una solución detallada. Entonces, una respuesta como "en DBMS-X, esto se puede hacer con disparadores en la tabla A" es perfectamente aceptable.