2009-11-13 6 views
2

Hier tout en travaillant sur un projet que je suis venu sur un 1 particulier: 1 relation qui m'a laissé se demander - comment mieux mettre en œuvre ce (clairement, nous avions fait mal: D)Comment mieux implémenter une relation 1: 1 dans un SGBDR?

L'idée est qu'il ya deux types d'entités, A et B. Ils peuvent chacun exister par eux-mêmes, mais ils peuvent aussi avoir un lien entre eux. S'il y a un lien, alors il doit s'agir d'un lien 1: 1, et travailler dans les deux sens.

C'est comme une bouteille et un bouchon. Ils peuvent exister à part, mais une fois couplés, la bouteille aura un seul bouchon, et le bouchon sera attaché à une seule bouteille (et la même).

Comment implémenteriez-vous cette relation tout en gardant à l'esprit toutes les meilleures pratiques en matière de normalisation, d'intégrité des données, etc.? Presque oublié de dire - ils ont chacun plus d'une douzaine de propriétés, donc les mettre dans la même table avec la moitié des champs étant NULL est une solution assez gênante. En outre, le lien peut être rompu et recréé avec une autre entité à tout moment.

+0

Ce que vous avez décrit est un nombre à plusieurs. Il y a beaucoup de bouteilles de Coca et beaucoup de bouchons de Coke. Tout bouchon de Coke convient à n'importe quelle bouteille de Coke, mais un bouchon de Coke spécifique est associé à une bouteille de Coke spécifique. Une vraie relation one-to-one signifie que nous avons deux entités séparées qui * ne peuvent exister ensemble *. Si nous avons une instance de l'entité A, nous devons avoir une et une seule instance correspondante de l'entité B; de plus, l'instance de l'entité B doit avoir une instance unique de l'entité A. Cela se produit généralement parce que l'entité B est un sous-type de l'entité A (comme l'entité C, D, etc.). – APC

Répondre

0

Nullable clé étrangère avec une contrainte unique à l'une ou les deux extrémités en fonction (aux extrémités Both est intéressant!)

+0

Oui, c'est ce que nous avons maintenant. Une clé étrangère aux deux extrémités. C'est aussi gênant quand vous essayez d'établir/rompre un lien. Doit recourir aux trucs des déclencheurs. J'espérais une arme plus élégante ... –

+0

Pourquoi maladroit? Deux mises à jour dans une seule transaction devraient vous permettre de rompre et/ou de reconfigurer un lien. –

+0

Exactement. Deux mises à jour Gênant. :) –

7

Pour résoudre ce problème, je commencerais par la norme many-to-many mise en relation. J'utiliserais alors des déclencheurs, des index uniques, des contraintes pour appliquer la relation 1: 1 dans la table. La méthode exacte dépendra des besoins du système.

La raison pour laquelle j'aime ce format est que de nombreuses relations ont des attributs dans le cadre de la relation qui ne font pas partie des entités. Ce modèle permet cela maintenant et dans le futur.

Par exemple: une personne travaille pour une entreprise. La relation a une date d'embauche qui ne correspond pas à l'entité personne ou l'entité de la société.

+0

Jusqu'à présent, le meilleur! –

2

Je pense que le schéma ressemblerait à ceci:

create table A (
    A_id integer primary key, 
    ... 
); 

create table B (
    B_id integer primary key, 
    A_id integer references A (A_id), 
    ... 
); 

alter table B add constraint c1 unique(A_id); 

B ne peut faire référence à une ligne dans A, et puisque le champ est unique, ne peut être référencé par une ligne dans B.

B.Aid est nullable, donc des lignes peuvent exister dans A et B qui ne se réfèrent pas mutuellement.

La contrainte d'unicité n'exclut pas l'existence de plusieurs enregistrements NULL. Une contrainte unique garantit que les valeurs sont toutes uniques ou NULL.

+0

Mais comme il est unique, vous ne pouvez pas avoir deux lignes avec des valeurs nulles! –

+0

@spoonmeiser: ma réponse ne tenait pas cette exigence supplémentaire, je suppose que je l'ai lu, je l'ai supprimé car il n'était pas utile pour cette question, tx pour votre remakr – Peter

+0

@Vilx: oui vous pouvez. Une contrainte unique implique que toutes les valeurs sont uniques, mais vous pouvez avoir plusieurs valeurs NULL car vous ne pouvez pas comparer NULL à NULL. – SpoonMeiser

0

Table de jointure séparée de clé étrangère référençant A contre clé étrangère référençant B, les deux colonnes avec contrainte UNIQUE. Ainsi, soit un lien existe entre deux entités et est le seul lien pour l'un ou l'autre, soit aucun lien existe donc il n'y a pas de ligne dans la table.

+0

Umm ... trop lent? –

+0

Umm. . . @ Vilx? C'est la * même * solution que celle de Darryl que vous venez de féliciter! –

+0

C'est ce que je veux dire. Vous étiez trop lent à poster ceci et quelqu'un d'autre a déjà soumis exactement la même solution ... 20 minutes plus tôt. –

0

j'utiliser la solution proposée par Darryl:

TableA 
    AId 
    AInfo 

TableB 
    BId 
    BInfo 

TableA2B 
    AId 
    BId 

puis il suffit d'ajouter Contraindre unique sur AId dans tableA2B et Bid sur tableA2B

alter TableA2B add constraint ucAId unique(AId) 
alter TableA2B add constraint ucBId unique(BId) 

Je pense que cela résoudrait votre problème

Les entrées tableA qui ne sont liées à aucune entrée de tableB ne seraient tout simplement pas présentes dans les entrées TableB de la même façon que les entrées tableB non liées à tableA.

Les contraintes exécuteraient maximum un lien de tableA à tableB ou tableB à tableA

2
CREATE TABLE A (id INT NOT NULL PRIMARY KEY, field1, …) 

CREATE TABLE B (id INT NOT NULL PRIMARY KEY, field1, …) 

CREATE TABLE AB (aid INT NOT NULL, bid INT NOT NULL, 
       CONSTRAINT pk_ab PRIMARY KEY (aid, bid), 
       CONSTRAINT ux_a UNIQUE (aid), 
       CONSTRAINT ux_b UNIQUE (bid), 
       CONSTRAINT fk_aid_a FOREIGN KEY (aid) REFERENCES A, 
       CONSTRAINT fk_bid_b FOREIGN KEY (bid) REFERENCES B 
       ) 
0

Il y a deux cas différents de l'OMI à prendre en compte. Le premier cas est le mieux illustré avec un mariage monogame: les deux objets sont créés indépendamment, et à un moment donné, ils sont joints; plus tard, ils pourraient être détachés et éventuellement associés à d'autres objets. Pour une telle relation, je proposerais l'approche de la table A2B utilisée par beaucoup d'autres ici.

Le deuxième cas est représenté avec des jumeaux: si les deux objets sont connectés, ils le sont depuis la naissance et ils le sont jusqu'à la mort de l'un d'entre eux. Dans ce cas, vous pouvez choisir de leur donner simplement la même clé primaire lors de la création (par exemple, dans Oracle en sélectionnant une valeur dans une séquence et en l'utilisant comme ID pour les deux tables).

0

"Une clé étrangère aux deux extrémités, c'est aussi gênant quand vous essayez d'établir/de rompre un lien, de recourir à des éléments déclencheurs, j'espérais une arme plus élégante." Vous ne trouverez pas une telle arme élégante dans l'univers des systèmes basés sur SQL.

La réponse de Darryl Peterson montre la solution logiquement correcte. Mais certains cas de "changement de lien" peuvent devenir un cauchemar dans SQL en raison de son manque de soutien pour le concept TTM de "cession multiple".

Questions connexes