7
votes

Touches étrangères multiples mais mutuellement exclusives - est-ce la voie à suivre?

J'ai trois tables: utilisateurs, entreprises et sites Web. Les utilisateurs et les entreprises ont des sites Web, et donc chaque enregistrement d'utilisateur a une clé étrangère dans la table des sites Web. En outre, chaque enregistrement de la société a une clé étrangère dans la table des sites Web.

Maintenant, je veux inclure des clés étrangères dans la table des sites Web dans leurs enregistrements "parents" respectifs. Comment je fais ça? Dois-je avoir deux clés étrangères dans chaque enregistrement de sites Web, avec l'un d'entre eux toujours NULL? Ou y a-t-il une autre façon d'aller?


0 commentaires

6 Réponses :


2
votes

Pourquoi avez-vous besoin d'une clé étrangère du site Web à l'utilisateur / à la société? Le principe de non-duplication des données suggérerait qu'il serait peut-être préférable de numériser les tables d'utilisateur / société pour un identifiant de site Web correspondant. Si vous avez vraiment besoin de vous pouvez toujours stocker un drapeau dans la table du site Web qui indique si un enregistrement de site Web donné est destiné à un utilisateur ou à une entreprise, puis numérisez la table appropriée.


0 commentaires

7
votes

Vous n'avez pas besoin d'une colonne parent, vous pouvez consulter les parents avec une simple sélection (ou rejoindre les tables) sur la table des utilisateurs et des entreprises. Si vous souhaitez savoir s'il s'agit d'un utilisateur ou d'un site Web d'entreprise, je suggère d'utiliser une colonne booléenne dans votre table de sites Web.


1 commentaires

+1 - très bien exactement ce que j'ai dit, alors je pense clairement que tu as raison!



1
votes

Tout d'abord, avez-vous vraiment besoin de ce lien bidirectionnel? C'est une bonne pratique pour l'éviter sauf absolument nécessaire.

Je comprends que vous souhaitez savoir si le site appartient à un utilisateur ou à une entreprise. Vous pouvez y parvenir, en ayant un simple champ booléen dans la table du site Web - [HeomeStticer]. Si c'est vrai, alors vous recherchez un utilisateur, si faux - vous recherchez une entreprise.


0 commentaires

12
votes

Si nous examinons le modèle ici, nous verrons ce qui suit:

  1. Un utilisateur est lié à exactement un site web
    • Une entreprise est liée à exactement un site Web
    • Un site Web est lié à exactement un utilisateur ou une entreprise

      la troisième relation implique une existence d'une entité "utilisateur ou société" dont la clé primaire doit être stockée quelque part.

      Pour le stocker, vous devez créer un Table qui stockerait une clé principale d'un propriétaire de site Web . Ce tableau peut également stocker des attributs communs à un utilisateur et un site Web.

      Comme il s'agit d'une relation individuelle, les attributs de site Web peuvent également être stockés dans ce tableau.

      Les attributs Non partagé par les utilisateurs et les entreprises doit être stocké dans la table séparée.

      Pour forcer les relations correctes, vous devez effectuer la touche principale du site Web > composite avec Type de propriétaire en tant que partie de celui-ci et forcez le type correct dans les tables enfant avec un vérifier contrainte: xxx


2 commentaires

"Forcer le type correct dans les tables enfants avec une contrainte de contrôle" - Celles-ci ne sont pas appliquées dans MySQL, non?


@Enedaywhen: Non, ils ne sont pas.



2
votes

Le problème que j'ai avec la réponse acceptée (par quassnoi) est que les relations d'objet sont dans le mauvais sens: la société n'est pas un sous-type de propriétaire d'un site Web; Nous avions des entreprises avant d'avoir des sites Web et nous pouvons avoir des entreprises qui sont des propriétaires de sites Web. En outre, il me semble que la propriété du site Web est une relation entre un site Web et une personne ou une entreprise, c'est-à-dire que nous devrions avoir une table de relations (ou deux) dans le schéma. Il peut s'agir d'une approche acceptable de conserver la propriété de site Web personnelle séparément de la propriété du site internet de l'entreprise et de les apporter uniquement lorsque vous avez besoin de par exemple. via affichage s: xxx

Le problème avec ce qui précède est qu'il n'ya aucun moyen d'utiliser des contraintes de base de données pour appliquer la règle selon laquelle un site Web est détenu par une personne ou une entreprise mais pas à la fois.

Si nous pouvons supposer que les DBMS appliquent les contraintes de vérification (comme la réponse acceptée, nous pouvons exploiter le fait qu'une personne (humaine) et une entreprise sont à la fois des personnes morales et utilisées. une table de super type ( légales ) mais conserver toujours une approche de la table de relation ( site Web ), cette fois à l'aide de la vue S pour séparer les propriétaires de sites Web personnels De séparé de la propriété du site internet de l'entreprise, mais cette fois avec des attributs fortement dactylographiés: xxx

Ce dont nous avons besoin sont de nouvelles fonctionnalités SGMS pour "clés étrangères distribuées" ("pour chaque ligne de cette table Il doit y avoir exactement une ligne dans l'une de ces tables ") et" moindre affectation "pour permettre d'ajouter les données dans des tables ainsi contractées dans une seule instruction SQL. Malheureusement, nous sommes loin d'obtenir de telles fonctionnalités!


0 commentaires

0
votes

Un peu en retard, mais toutes les réponses existantes semblaient tomber un peu à cause de la marque:

  • propriétaire du site Web est un 1: beaucoup code> relation li>
  • Site Web au propriétaire est un 1: 1 code> relation li>
  • Les tables des utilisateurs et des entreprises ne doivent pas avoir une clé étrangère dans la table des sites Web LI>
  • Aucune des données de site Web, communes aux utilisateurs et aux entreprises ou non, devrait être dans les tableaux d'utilisateurs ou de sociétés li>
  • Aucune information du propriétaire, commune ou non, devrait être dans la table des sites Web li>
  • mysql ignore, silencieusement, vérifier code> des contraintes sur les tables (aucune application de l'intégrité référentielle) li>
  • Le SGBD doit gérer la logique "Relation", pas l'application à l'aide de la base de données li> ul>

    Une partie de celle-ci est reconnue dans le Réponse de Onedaywhen , mais que La réponse a toujours manqué l'occasion de rendre MySQL faire la forte levée et d'appliquer l'intégrité référentielle. p>


    Un site Web ne peut avoir qu'un propriétaire, légalement, de toute façon. Une personne ou une entreprise, peut avoir un nombre quelconque de sites Web, y compris aucun. Un lien dans la base de données du propriétaire du site Web ne peut être que 1: 1 code> à n'importe quel niveau de normalisation. En réalité, la relation est 1: beaucoup code> et nécessiterait de disposer d'entrées de table multiples pour chaque propriétaire qui s'appuie sur plusieurs sites Web. Un lien du site Web au propriétaire est 1: 1 code> dans les deux termes de la base de données et en réalité. Avoir le lien du site Web au propriétaire représente le modèle mieux. Avec un index dans la table du site Web, faire le 1: nombre code> pour un propriétaire donné devient raisonnablement efficace. P>

    L'attribut cocher code> dans SQL serait Une excellente solution, si MySQL n'était pas arrivée à l'ignorer silencieusement. P>

    MySQL Docs 13.1.20 Créer une syntaxe de table SUB> P>

    La clause cocher code> est analysée mais ignorée par tous les moteurs de stockage. P> blockQuote>

    La fonctionnalité de MySQL offre deux solutions comme des contours pour mettre en œuvre le comportement de vérifier code> et conserver l'intégrité référentielle des données. Les déclencheurs avec des procédures stockées en sont une et fonctionne bien avec toutes sortes de contraintes. Plus facile à mettre en œuvre, bien que moins polyvalent, utilise une vue code> avec un avec l'option de contrôle code>, que mysql sera em> mise en œuvre. P> MYSQL DOCS 24.5.4 Vue avec option de contrôle Clause SUB> P>

    Le avec l'option de contrôle code> peut être donné pour une vue mise à jour pour empêcher les insertions des lignes pour lesquelles la clause où code> dans le select_statement code> em> n'est pas vrai. Il empêche également les mises à jour des lignes pour lesquelles le où la clause code> est vrai, mais la mise à jour ne serait pas vraie (en d'autres termes, elle empêche les lignes visibles d'être mises à jour sur des lignes non visibles). P > BlockQuote>

    Le site MySQLTutorial donne un bon exemple des deux options de leur Introduction à la contrainte de vérification SQL tutoriel. (Vous devez penser à la faute de frappe, mais bon sinon.) P>


    avoir trouvé cette question en essayant de résoudre une scission de clé étrangère mutuellement exclusive similaire et de développer une solution, avec des notes générées par les réponses. , il semble seulement de partager ma solution en retour. p>

    solution recommandée h2>

    pour l'impact minimum sur le schéma existant et l'application accédant aux données, conserver les utilisateurs code> et entreprises code> Tables tels qu'ils sont. Renommez les sites Web code> code> et remplacez-le par une vue nommée Sites Web code> que l'application peut continuer à accéder. Sauf lors de la gestion des informations de propriété, toutes les anciennes requêtes à Les sites Web CODE> doivent toujours fonctionner. Donc: P>

    la configuration h3> xxx pré>

    utilisation h3> xxx pré>

    niveau de normalisation UP H2>

    comme une note technique pour la normalisation, les informations de propriété pourraient être prises en compte sur la table des sites Web et une nouvelle table créée pour contenir les données de propriété, y compris la colonne IS_NORMAL. P>

    CREATE TABLE `Websites` (
        `id` SERIAL PRIMARY KEY,
        `name` VARCHAR(255),
        `owner` BIGINT UNSIGNED DEFAULT NULL,
        website_attributes,
        FOREIGN KEY `Website_Owner` (`owner`)
            REFERENCES `WebOwners` (id`)
                ON DELETE RESTRICT ON UPDATE CASCADE
    );
    
    CREATE TABLE `WebOwnersData` (
        `id` SERIAL PRIMARY KEY,
        `is_personal` BOOL,
        `user` BIGINT UNSIGNED DEFAULT NULL,
        `company` BIGINT UNSIGNED DEFAULT NULL,
        FOREIGN KEY `WebOwners_User` (`user`)
            REFERENCES `Users` (`id`)
                ON DELETE RESTRICT ON UPDATE CASCADE,
        FOREIGN KEY `WebOwners_Company` (`company`)
            REFERENCES `Companies` (`id`)
                ON DELETE RESTRICT ON UPDATE CASCADE,
    );
    
    CREATE VIEW `WebOwners` AS
    SELECT * FROM WebsitesData WHERE
        (`is_personal`=TRUE AND `user` IS NOT NULL AND `company` IS NULL) OR
        (`is_personal`=FALSE AND `user` IS NULL AND `company` IS NOT NULL)
    WITH CHECK OPTION;
    


2 commentaires

Bonjour, cette solution n'est pas correcte de la normalisation et du point de vue conceptuel. Vous avez ajouté une colonne supplémentaire qui n'a aucune signification dans le contexte commercial et je pense que c'est redondant, même dans votre solution. Et vous avez tellement de clés étrangères nulles (lorsque la base de données a progressivement augmenté). Et si nous avons 4 ou 5 clés étrangères mutuellement exclusives dans une table?


@Arash n'est pas sûr de quelle colonne n'a pas de sens dans le contexte de l'entreprise et, à ce moment-là que je savais à l'époque, il n'ya aucun moyen de faire appliquer MySQL un accord de clé étrangère mutuellement exclusif sans recourir à des procédures stockées, si même alors.