Mysql
 sql >> Base de données >  >> RDS >> Mysql

En SQL, est-il acceptable que deux tables se réfèrent l'une à l'autre ?

Non, ce n'est pas OK. Les références circulaires entre les tables sont désordonnées. Consultez cet article (vieux de dix ans) :SQL By Design :The Circular Reference

Certains SGBD peuvent les gérer, et avec un soin particulier, mais MySQL aura des problèmes.

Option 1

En tant que conception, pour rendre l'un des deux FK nullable. Cela vous permet de résoudre le problème de la poule et de l'œuf (dans quel tableau dois-je d'abord insérer ?).

Il y a cependant un problème avec votre code. Cela permettra à un produit d'avoir une image par défaut où cette image fera référence à un autre produit !

Pour interdire une telle erreur, votre contrainte FK doit être :

CONSTRAINT FK_products_1 
  FOREIGN KEY (id, default_picture_id) 
  REFERENCES products_pictures (product_id, id)
  ON DELETE RESTRICT                            --- the SET NULL options would 
  ON UPDATE RESTRICT                            --- lead to other issues

Cela nécessitera un UNIQUE contrainte/index dans la table products_pictures sur (product_id, id) pour que le FK ci-dessus soit défini et fonctionne correctement.

Option 2

Une autre approche consiste à supprimer le Default_Picture_ID colonne forme le product table et ajoutez un IsDefault BIT colonne dans l'picture table. Le problème avec cette solution est de savoir comment permettre à une seule image par produit d'avoir ce bit et à tous les autres de l'avoir. Dans SQL-Server (et je pense dans Postgres), cela peut être fait avec un index partiel :

CREATE UNIQUE INDEX is_DefaultPicture 
  ON products_pictures (Product_ID)
  WHERE IsDefault = 1 ;

Mais MySQL n'a pas une telle fonctionnalité.

Option 3

Cette approche vous permet même d'avoir les deux colonnes FK définies comme NOT NULL est d'utiliser des contraintes reportables. Cela fonctionne dans PostgreSQL et je pense dans Oracle. Vérifiez cette question et la réponse de @Erwin :Contrainte de clé étrangère complexe dans SQLAlchemy (le champ Toutes les colonnes clés NON NULLES partie).

Les contraintes dans MySQL ne peuvent pas être différées.

Option 4

L'approche (que je trouve la plus propre) consiste à supprimer le Default_Picture_ID colonne et ajouter une autre table. Aucun chemin circulaire dans les contraintes FK et toutes les colonnes FK seront NOT NULL avec cette solution :

product_default_picture
----------------------
product_id          NOT NULL
default_picture_id  NOT NULL
PRIMARY KEY (product_id)
FOREIGN KEY (product_id, default_picture_id)
  REFERENCES products_pictures (product_id, id)

Cela nécessitera également un UNIQUE contrainte/index dans la table products_pictures sur (product_id, id) comme dans la solution 1.

Pour résumer, avec MySQL, vous avez deux options :

  • option 1 (une colonne FK acceptant les valeurs nulles) avec la correction ci-dessus pour appliquer correctement l'intégrité

  • option 4 (aucune colonne FK acceptant les valeurs nulles)