Dis qu'il y a des entités appelées singulars
et entités appelées relationships
.
Il faut exactement deux singulars
pour constituer une entité relationships
.
C'est paire de singuliers ne peut pas être répété ailleurs dans relationships
, dans n'importe quel ordre.
Une façon de modéliser cela pourrait être de cette façon:
+----------------+
|relationships | +----------+
+----------------+ |singulars |
|id | +----------+
|singular_id_1 <---------+id |
|singular_id_2 <---+ |attribute1|
|pair_description| |attribute2|
|pair_date | | |
| | +----------+
+----------------+
Avec ce motif, il devient nécessaire de vérifier les deux champs de clé étrangers dans relationships
pour l'existence de singulars
, qui pourrait être de chaque côté. L'ordre n'a pas d'importance, mais il est défini dans le schéma ... afin que les requêtes se retrouvent avec un certain nombre de AND
/OR
groupes et cas.
L'expansion sur cette approche pourrait être de stocker deux enregistrements de chaque paire, avec le singular_id_[n]
échangé des deux côtés. Bien que cela résout certaines complexités interrogées, cela introduirait des complexités supplémentaires pour le rendre infaisable.
L'utilisation d'une table intermédiaire semble être une solution potentielle:
+----------------+ +-----------------------+
|relationships | |singulars_relationships| +----------+
+----------------+ +-----------------------+ |singulars |
|id <-------+relationship_id | +----------+
|pair_description| |singular_id +-------->id |
|pair_date | | | |attribute1|
| | +-----------------------+ |attribute2|
+----------------+ | |
+----------+
Les enregistrements peuvent donc finir par quelque chose comme ça:
+----------------------------------+
|relationships |
+----------------------------------+
|id pair_description pair_date |
+----------------------------------+
|1 Fizz buzz blitz 2022-02-20|
|2 Blitz buzz fizz 2022-02-22|
+----------------------------------+
+----------------------------------+
|singulars_relationships |
+----------------------------------+
|relationship_id singular_id |
+----------------------------------+
|1 1 |
|1 2 |
|2 3 |
|2 4 |
+----------------------------------+
+-----------------------------+
|singulars |
+-----------------------------+
|id attribute1 attribute2 |
+-----------------------------+
|1 Fizz Blitz |
|2 Buzz Foo |
|3 Bar World |
|4 Blorg Hello |
+-----------------------------+
Là, singulars_relationships
est l'endroit où les paires sont définies. Si un singular_id
existe là-bas, c'est déjà dans une paire. Un problème qui peut survenir avec ce modèle pourrait être que trois ou plus singular_id
s pourrait finir par associé à un relationship_id
, et la contrainte "exactement n" serait alors compromise.
Y a-t-il des termes officiels pour ce type de scénario? Et autre théorie et alternatives?
Y a-t-il des termes officiels pour ce type de scénario?
Oui. Ceci est une Relation symétrique . Et "relation" ici a la même signification que dans "Base de données relationnelle". Un RDBMS est un système de gestion de base de données conçu autour de la conservation des relations. Cependant, les RDBMS n'ont pas de manière native de stocker des relations symétriques. Vous devez soit stocker les deux tuples, par exemple (A, B) et (B, A) comme rangées séparées, ou vous devez utiliser une sorte de convention pour stocker un seul tuple. Une approche commune consiste à utiliser une contrainte de contrôle sur les FKS.
par exemple
check (singular_id_1 < singular_id_2)
En supposant que la relation soit anti-réflexive .
Pour un commentaire, je vais donc ajouter cela comme un complément à David's solution. Même si la question était de nature théorique, il peut être intéressant de voir comment cela peut être mis en œuvre dans la vie réelle.
Dans certaines situations, la propriété anti-réflexive et la propriété symétrique est trop forte, mais nous voulons toujours que la propriété "unicité" soit tenue. Un modèle commun est d'utiliser BEFORE TRIGGERS
Pour rendre la relation symétrique sans laisser les utilisateurs devoir être au courant de la propriété symétrique:
CREATE TRIGGER trigger1
BEFORE INSERT ON t
REFERENCING NEW AS N
FOR EACH ROW
SET (N.a, N.b) = (LEAST(N.a, N.b), GREATEST(N.a, N.b));
Propriétés dans le tableau:
CHECK(a<=b);
UNIQUE(a,b);
Une variante de ce thème consiste à utiliser des colonnes générées
CREATE TABLE t
( a int not null
, b int not null
, least_a_b generated always as ( least(a,b) )
, greatest_a_b generated always as ( greatest(a,b))
, unique (least_a_b, greatest_a_b)
);
Les colonnes générées peuvent également être cachées:
least_a_b generated always as ( least(a,b) ) IMPLICITLY HIDDEN
Des exemples proviennent de DB2, mais des fonctionnalités similaires devraient exister pour d'autres fournisseurs.