la dépendance circulaire mysql dans les contraintes clés étrangères

etant Donné le schéma:

enter image description here

ce dont j'ai besoin c'est d'avoir tous les user_identities.belongs_to référence users.id.

En même temps, tous les users a un primary_identity comme sur la photo.

Cependant lorsque j'essaie d'ajouter cette référence avec ON DELETE NO ACTION ON UPDATE NO ACTION, MySQL says

#1452-impossible d'ajouter ou de mettre à jour une rangée d'enfants: une contrainte de clé étrangère échoue (yap.#sql-a3b_1bf, CONSTRAINT #sql-a3b_1bf_ibfk_1 CLÉ ÉTRANGÈRE ( belongs_to) RÉFÉRENCES (id) ON DELETE NO ACTION ON UPDATE NO ACTION)

je suppose que c'est dû à la dépendance circulaire, mais comment pourrais-je le résoudre (et maintenir l'intégrité référentielle)?

13
demandé sur Flavius 2012-09-29 15:03:26

6 réponses

la seule façon de résoudre cela (au moins avec les capacités limitées de MySQL) pour permettre NULL valeurs dans les deux colonnes de FK. La création d'un nouvel utilisateur avec un primaire d'identité serait alors ressembler à quelque chose comme ceci:

insert into users (id, primary_identity)
values (1, null);

insert into identities (id, name, belongs_to)
values (1, 'foobar', 1);

update users 
  set primary_identity = 1
where id = 1;

commit;

le seul inconvénient de cette solution est que vous ne pouvez pas forcer qu'un utilisateur a une identité primaire (parce que la colonne doit être nullable).



une autre option serait de passer à un SGBD qui supporte les contraintes différées, ensuite, vous pouvez simplement insérer les deux lignes et la contrainte ne seront enregistrés au moment de la validation. Ou utiliser un SGBD où vous pouvez avoir un index partiel, alors vous pouvez utiliser la solution avec un is_primary colonne

7
répondu a_horse_with_no_name 2012-09-29 11:54:09

Je ne l'implémenterais pas de cette façon.

Supprimer le champ primary_identity tableau users, et l'ajout d'un champ supplémentaire à la table user_profilesis_primary, et utilisez plutôt ceci comme indicateur d'un profil primaire

6
répondu Adriaan Stander 2012-09-29 11:11:51

ceci empêchera D'avoir des NULL pour FKs, mais ne fait pas encore appliquer pour que le profil primaire existe -- cela doit être géré par application.

Remarque: l'autre touche (index unique) {UserID, ProfileID}Profile table et correspondant FK sur PrimaryProfile.

enter image description here

1
répondu Damir Sudarevic 2012-10-04 19:49:13

cette question a été posée à comment faire tomber des tables avec des clés étrangères cycliques dans MySQL à partir de la supprimer côté des choses, mais je pense que l'une des réponses est applicable ici:

SET foreign_key_checks = 0;
INSERT <user>
INSERT <user identity>
SET foreign_key_checks = 1;

faites une transaction et engagez tout d'un coup. Je n'ai pas essayé, mais il fonctionne pour les supprime, donc je ne sais pas pourquoi ça ne marcherait pas pour les insertions.

1
répondu Charles Wood 2017-05-23 12:34:25

je n'ai pas utilisé, mais vous pouvez essayer INSERT IGNORE. Je ferais ces deux-là, un pour chaque table, de sorte qu'une fois les deux faits, l'intégrité référentielle soit maintenue. Si vous les faites dans une transaction, vous pouvez revenir en arrière s'il y a un problème d'insertion de la seconde.

puisque vous ignorez les contraintes avec cette fonctionnalité, vous devriez plutôt vérifier le code du programme, sinon vous pourriez vous retrouver avec des données dans votre base de données qui ignorent votre contraintes.

merci à @Mihai pour avoir souligné le problème avec ce qui précède. Une autre approche serait de désactiver les contraintes pendant que vous faites des inserts, et de les réactiver par la suite. Cependant, sur une grande table qui peut produire plus de ressources qu'est acceptable d'essayer?

0
répondu halfer 2012-09-29 19:12:01

le problème semble être que vous essayez de garder les informations d'identité primaires dans la table user_identities.

à la place, je vous suggère de mettre l'information utilisateur primaire (nom/courriel) dans la table des utilisateurs. N'avez pas de clé étrangère à la user_identities table.

seule clé étrangère de la table user_identities

toutes les contraintes vont maintenant fonctionner correctement car elles ne sont qu'une seule façon.

identités_utilisateurs ne peuvent être saisies que si l'utilisateur primaire (en utilisateurs de la table) est présent. De même, l'utilisateur principal ne doit pas être deletable lorsqu'il existe des identités d'enfants (dans user_identities).

vous pourriez vouloir changer le nom des tables en "primary_users" et "secondary_users" pour rendre évident ce qui se passe.

est-ce que ça va?

0
répondu emperorz 2012-10-01 09:36:37