MySQL-Une Relation À Une?

Maintenant, je sais qu'il y a des réponses à propos D'une Relation à une, mais aucun d'entre eux n'a répondu à ma question, alors veuillez lire ceci avant le vote:)

J'essaie d'atteindre une relation à une dans la base de données MySQL. Par exemple, disons que j'ai une table D'utilisateurs et une Table de comptes. Et je veux être sûr Qu'il y a un utilisateur qui ne peut avoir qu'un seul compte. Et qu'il peut y avoir qu'un seul Compte par utilisateur.

J'ai trouvé deux solutions pour cela mais je ne sais pas quoi utiliser, et y en a-t-il d'autres option.

Première solution:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    user_id INT UNIQUE,
    PRIMARY KEY(id),
    FOREIGN KEY(user_id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

Dans cet exemple, je définis la clé étrangère dans les comptes pointant vers la clé primaire dans les utilisateurs. Et puis je rends la clé étrangère UNIQUE, donc il ne peut pas y avoir deux utilisateurs identiques dans les comptes. Pour joindre des tables, j'utiliserais cette requête:

SELECT * FROM users JOIN accounts ON users.id = accounts.user_id;

Deuxième solution:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id),
    FOREIGN KEY(id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

Dans cet exemple, je crée une clé étrangère qui pointe de la clé primaire vers une clé primaire dans une autre table. Puisque les clés primaires sont uniques par défaut, cela rend cette relation unique à Un. Pour joindre des tables je peux utiliser ceci:

SELECT * FROM users JOIN accounts ON users.id = accounts.id;

Maintenant, les questions:

  • Quelle est la meilleure façon de créer une relation One To One dans MySQL?
  • y a-t-il d'autres solutions que ces deux-là?

J'utilise MySQL Workbench, et quand je conçois une relation à une dans le diagramme EER, et laisse MySQL Workbench produire du code SQL, j'obtiens une relation à plusieurs: S c'est ce qui me déroute: S

Et si j'importe l'une de ces solutions dans MySQL Workbench EER diagramme, il reconnaît les relations comme un à plusieurs: S C'est aussi déroutant.

Alors, quelle serait la meilleure façon de définir une relation à une dans MySQL DDL. Et quelles sont les options pour y parvenir?

Merci!!

48
demandé sur Salman A 2012-11-30 16:09:00

3 réponses

Puisque les clés primaires sont uniques par défaut, cela rend cette relation une à une.

Non, cela rend la relation "un à zéro ou un". C'est ce dont vous avez vraiment besoin?

Si Oui , alors votre "deuxième solution" est meilleure:

  • , c'est plus simple,
  • prend moins de stockage1 (et rend donc le cache "plus grand")
  • HES moins d'index à maintenir2, Quels avantages la manipulation des données,
  • et (puisque vous utilisez InnoDB) naturellement clusters les données, de sorte que les utilisateurs proches auront leurs comptes stockés proches les uns des autres, ce qui peut bénéficier à la localisation du cache et à certains types d'analyses de plage.

BTW, vous devrez faire accounts.id un entier ordinaire (pas auto-incrément) pour que cela fonctionne.

Si non, voir ci-dessous...

Quelle est la meilleure façon de créer une relation One To One dans MySQL?

Eh bien, "meilleur" est un mot surchargé, mais la solution" standard " serait la même que dans toute autre base de données: mettez les deux entités (utilisateur et compte dans votre cas) dans la même table physique.

Y a-t-il d'autres solutions que ces deux?

Théoriquement, vous pourriez faire des FK circulaires entre les deux PK, mais cela nécessiterait des contraintesdifférées pour résoudre le problème du poulet et de l'œuf, qui ne sont malheureusement pas supportés sous MySQL.

Et si j'importe l'un de ces solutions dans MySQL Workbench EER diagramme, il reconnaît les relations comme un à plusieurs: S C'est aussi déroutant.

Je n'ai pas beaucoup d'expérience pratique avec cet outil de modélisation particulier, mais je suppose que c'est parce que c'est "un à plusieurs" où le côté "beaucoup" a été plafonné à 1 en le rendant unique. Rappelez-vous que "plusieurs" ne signifie pas" 1 ou plusieurs", cela signifie" 0 ou plusieurs", donc la version" plafonnée "signifie vraiment" 0 ou 1".


1 Pas seulement dans le stockage frais pour le champ supplémentaire, mais aussi pour l'index secondaire. Et puisque vous utilisez InnoDB qui cluster toujours les tables , méfiez-vous que les index secondaires sont encore plus chers dans les tables en cluster que dans les tables basées sur des tas.

2 InnoDB requiert index sur les clés étrangères.

36
répondu Branko Dimitrijevic 2012-11-30 12:51:01

Votre première approche crée deux clés candidates dans la table des comptes: id et user_id.

Je suggère donc la deuxième approche à savoir utiliser la clé étrangère comme clé primaire. Ce:

  • utilise une colonne de moins
  • vous permet d'identifier de manière unique chaque ligne
  • vous permet de faire correspondre le compte avec l'utilisateur
7
répondu Salman A 2012-11-30 12:17:00

Qu'en est - il de l'approche suivante

  1. Créer un utilisateur de Table

    CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  2. Créer des comptes de la Table avec un index unique sur user_id et account_id avec une clé étrangère de la relation utilisateur/compte et une clé primaire sur user_id and account_id

    CREATE TABLE `account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  3. Créer la Table user2account

    CREATE TABLE `user2account` (
      `user_id` int(11) NOT NULL,
      `account_id` int(11) NOT NULL,
      PRIMARY KEY (`user_id`,`account_id`),
      UNIQUE KEY `FK_account_idx` (`account_id`),
      UNIQUE KEY `FK_user_idx` (`user_id`),
      CONSTRAINT `FK_account` FOREIGN KEY (`account_id`) REFERENCES         `account` (`id`),
      CONSTRAINT `FK_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

Bien que cette solution ait la plus grande empreinte dans la base de données, il y a quelques avantages.

  • mettre la FK_Key dans la table utilisateur ou le la table de compte est quelque chose que je m'attends à être un à plusieurs releation (l'Utilisateur a beaucoup de comptes ...)
  • Bien que cette approche user2account soit principalement utilisée pour définir une relation plusieurs à plusieurs, l'ajout d'une contrainte UNIQUE sur user_id et sur account_id empêchera de créer autre chose qu'une relation un à un.

Le principal avantage que je vois dans cette solution est que vous pouvez diviser le travail en différentes couches de code ou départements dans une entreprise

  • département a est responsable de la création d'utilisateurs, cela est possible même sans autorisation d'écriture à la table des comptes
  • Le Département B est responsable de la création des comptes, ceci est possible même sans autorisation d'écriture à la table Utilisateur
  • le département C est responsable de la création du mappage, ceci est possible même sans autorisation d'écriture sur la table utilisateur ou compte
  • Une fois que le département C a créé un mappage, ni l'utilisateur ni le compte ne peuvent être supprimés par le département A ou B sans demander au département C de supprimer le mappage en premier.
-2
répondu Jürgen Steinblock 2017-05-29 13:26:33