Inspiré d'une question de modélisation Django: Modélisation de base de données avec plusieurs relations plusieurs-à-plusieurs dans Django . Le db-design est quelque chose comme:
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)
) ;
et le problème est de savoir comment définir la BookAspectRating
table et appliquer l'intégrité référentielle, de sorte que l'on ne peut pas ajouter de note pour une (Book, Aspect)
combinaison non valide.
AFAIK, les CHECK
contraintes complexes (ou ASSERTIONS
) qui impliquent des sous-requêtes et plus d'une table, qui pourraient éventuellement résoudre ce problème, ne sont disponibles dans aucun SGBD.
Une autre idée est d'utiliser (pseudocode) une vue:
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) ;
et une table qui a une clé étrangère vers la vue ci-dessus:
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)
) ;
Trois questions:
Existe-t-il des SGBD qui permettent un (éventuellement matérialisé)
VIEW
avec unPRIMARY KEY
?Y at - il un SGBD qui permettent un
FOREIGN KEY
queREFERENCES
unVIEW
(et non seulement une baseTABLE
)?Ce problème d'intégrité pourrait-il être résolu autrement - avec les fonctionnalités de SGBD disponibles?
Clarification:
Puisqu'il n'y a probablement pas de solution 100% satisfaisante - et la question Django n'est même pas la mienne! - Je suis plus intéressé par une stratégie générale d'attaque possible du problème, pas par une solution détaillée. Ainsi, une réponse comme «dans SGBD-X, cela peut être fait avec des déclencheurs sur la table A» est parfaitement acceptable.
la source
Réponses:
Cette règle métier peut être appliquée dans le modèle en utilisant uniquement des contraintes. Le tableau suivant devrait résoudre votre problème. Utilisez-le à la place de votre vue:
la source
TagID
par un autre Tag lié à la même combinaison BookAspect.Je pense que vous constaterez que dans de nombreux cas, des règles commerciales complexes ne peuvent pas être appliquées via le seul modèle. C'est l'un de ces cas où, au moins dans SQL Server, je pense qu'un déclencheur (de préférence un au lieu d'un déclencheur) sert mieux votre objectif.
la source
Dans Oracle, une façon d'imposer ce type de contrainte de manière déclarative serait de créer une vue matérialisée qui est définie pour s'actualiser rapidement lors de la validation dont la requête identifie toutes les lignes non valides (c'est-à-dire les
BookAspectRating
lignes sans correspondanceBookAspect_view
). Vous pouvez ensuite créer une contrainte triviale sur cette vue matérialisée qui serait violée s'il y avait des lignes dans la vue matérialisée. Cela a l'avantage de minimiser la quantité de données que vous devez dupliquer dans la vue matérialisée. Cependant, cela peut poser des problèmes, car la contrainte n'est appliquée qu'au moment où vous validez la transaction - de nombreuses applications ne sont pas écrites pour s'attendre à ce qu'une opération de validation puisse échouer - et parce que la violation de la contrainte peut être quelque peu difficile à associer à une ligne ou une table particulière.la source
SIRA_PRISE permet cela.
Bien que le FK ne soit plus appelé "FK", mais simplement "contrainte de base de données", et la "vue" n'a en fait même pas besoin d'être définie comme une vue, vous pouvez simplement inclure l'expression définissant la vue dans la déclaration de la contrainte de base de données.
Votre contrainte ressemblerait à quelque chose
et tu as fini.
Dans la plupart des SGBD SQL, cependant, vous devrez effectuer le travail d'analyse sur votre contrainte, déterminer comment elle peut être violée et implémenter tous les déclencheurs nécessaires.
la source
Dans PostgreSQL, je ne peux pas imaginer une solution sans impliquer de déclencheurs, mais elle peut certainement être résolue de cette façon (que ce soit en maintenant une vue matérialisée d'une sorte ou un déclencheur avant
BookAspectRating
). Il n'y a pas de clé étrangère référençant une vue (ERROR: referenced relation "v_munkalap" is not a table
), encore moins une clé primaire.la source