2009-12-30 6 views
2

J'ai une table my_table avec ces champs: id_a, id_b. Cette table peut donc référencer soit une ligne de table_a avec id_a, soit une ligne de table_b avec id_b. Si je référence une ligne de table_a, id_b est NULL. Si je référence une ligne de table_b, id_a est NULL.Comment résoudre le problème de la clé A/B?

Actuellement, je pense que c'est ma seule/meilleure option que j'ai, donc dans ma table (qui a beaucoup plus d'autres champs, btw) Je vais vivre avec le fait que toujours un champ est NULL.

Si cela vous intéresse: Si id_a est spécifié, je suis lié à un jeu d'enregistrements "type de données" dans ma base de métadonnées, qui spécifie un type de données particulier. comme varchar (40), par exemple. Mais si id_b est spécifié, je suis lié à un jeu d'enregistrements de définition de relation qui spécifie des détails sur une relation (quand c'est 1: 1, 1: n, liant quoi, avec quelles contraintes, etc.). Les champs sont appelés un peu mieux, bien sûr;) ... essayez simplement de simplifier le problème. Edit: Si c'est important: MySQL, dernière version. Mais je ne veux pas limiter autant que possible ma conception au code spécifique de MySQL.

Y a-t-il de meilleures solutions?

Répondre

4

A et B sont des sous-types disjoints dans votre modèle.

Cela peut être mis en œuvre comme ceci:

refs (
     type CHAR(1) NOT NULL, ref INT NOT NULL, 
     PRIMARY KEY (type, ref), 
     CHECK (type IN ('A', 'B')) 
     ) 

table_a (
     type CHAR(1) NOT NULL, id INT NOT NULL, 
     PRIMARY KEY (id), 
     FOREIGN KEY (type, id) REFERENCES refs (type, id), 
     CHECK (type = 'A'), 
     …) 

table_b (
     type CHAR(1) NOT NULL, id INT NOT NULL, 
     PRIMARY KEY (id), 
     FOREIGN KEY (type, id) REFERENCES refs (type, id) ON DELETE CASCADE, 
     CHECK (type = 'B'), 
     …) 

mytable (
     type CHAR(1) NOT NULL, ref INT NOT NULL, 
     FOREIGN KEY (type, ref) REFERENCES refs (type, id) ON DELETE CASCADE, 
     CHECK (type IN ('A', 'B')), 
     …) 

Tableau refs constains toutes les instances des deux A et B. Il ne sert à rien d'autre qu'à surveiller l'intégrité référentielle, il ne participera même pas aux jointures.

Notez que MySQL accepte les contraintes CHECK mais ne les applique pas. Vous aurez besoin de regarder vos types.

Vous ne devriez pas supprimer les enregistrements de table_a et table_b directement: au lieu, supprimer les enregistrements de refs qui déclencheront ON DELETE CASCADE.

+0

wow, merci! est ce SQL standard, ou devrais-je coller ma conception à MySQL en utilisant ceci? – openfrog

+0

Ceci est standard 'SQL', mais' MySQL' ne supporte pas tout cela. Les 'CHECKs' ne fonctionneront pas du tout dans' MySQL', et 'FOREIGN KEYs' ne fonctionnera que dans les tables' InnoDB'. Dans tous les autres moteurs principaux, tout ce qui précède fonctionne correctement. – Quassnoi

1

Oui, il existe de meilleures solutions. Cependant, comme vous n'avez pas décrit ce que vous êtes autorisé à modifier, il est difficile de savoir quelles alternatives pourraient être utilisées. Principalement, ce type de référence clé "exclusif-ou" signifie que A et B sont en réalité deux sous-classes d'une super-classe commune. Vous avez plusieurs façons de modifier les tables A et B pour les unifier en une seule table.

L'un d'eux consiste simplement à fusionner les tables A et B en une grande table.

Un autre est d'avoir une table de super-classe avec les caractéristiques communes de A et B ainsi qu'un drapeau de sous-type qui indique quel sous-type il est. Ceci implique toujours une jointure avec la table de sous-classe, mais la jointure a un discriminateur explicite, et peut être faite "paresseusement" par l'application plutôt que dans le SQL.

+0

Je suppose que vous suggérez quelque chose comme Quassnoi suggéré? – openfrog

+0

@Quassnoi montre la technique "indicateur de type explicite". Cependant, cette solution ne restructure pas les tables A et B, ce qui est une manière complètement différente de résoudre votre problème. –

0

Je ne vois aucun problème avec votre solution. Cependant, je pense que vous devriez ajouter des contraintes CHECK pour vous assurer que exactement l'un des champs est null.

2

Créez une table "super-type" parente pour A et B. Référencez cette table dans table_mon.

0

vous savez, il est difficile de dire s'il existe de meilleures solutions depuis que vous avez éliminé la question de toutes les informations vitales. avec la petite quantité qui est toujours là, je dirais que les meilleures solutions impliquent de se débarrasser de my_table.

+0

my_table a beaucoup de champs supplémentaires, en fait c'est la définition d'un attribut de classe. attr_id, class_id, name, type_données_id, relation_definition_id (où les deux derniers sont cette chose A/B) – openfrog

Questions connexes