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

MYSQL - Une colonne référencée à plusieurs tables

Une réponse très tardive, mais pour ceux qui se demandent et recherchent sur Google.

OUI cela peut être fait, mais ce n'est PAS bonne pratique et même si c'est assez simple, ça va probablement vous exploser au visage si vous n'êtes pas très conscient de ce que vous faites. Non recommandé.

Cependant, je peux voir des utilisations. Par exemple, vous avez une grande table de millions d'enregistrements, et vous voulez, dans des cas exceptionnels, un lien vers des tables inconnues ou multiples (auquel cas il vaut mieux être beaucoup ). Avec plusieurs tables, si vous créiez une clé étrangère pour chacune d'entre elles, la taille de votre base de données augmenterait énormément. Une table inconnue serait possible par exemple dans un système de support technique, où vous souhaitez créer un lien vers un enregistrement dans une table où il pourrait y avoir un problème, et cela pourrait être (presque) toutes les tables de la base de données, y compris les futures.

Bien sûr, vous aurez besoin de deux champs à lier :un champ de clé étrangère et le nom de la table à laquelle il est lié. Appelons-les foreignId et linkedTable

linkedTable peut être une énumération ou une chaîne, de préférence une énumération (moins d'espace), mais cela n'est possible que si les différentes tables auxquelles vous souhaitez créer un lien sont fixes.

Donnons un exemple extrêmement idiot. Vous avez une énorme table d'utilisateurs users dont certains utilisateurs peuvent ajouter exactement un ensemble de données personnelles à leur profil. Il peut s'agir d'un passe-temps, d'un animal de compagnie, d'un sport qu'ils pratiquent ou leur métier. Maintenant, cette information est différente dans les quatre cas. (4 tables possibles n'est en réalité pas suffisant pour justifier cette structure)

Disons maintenant linkedTable est une énumération avec des valeurs possibles pets , hobbies , sports et professions , qui sont les noms de quatre tables structurées différemment. Disons id est le pkey dans chacun d'eux.

Vous rejoignez par exemple comme suit :

SELECT * FROM users 
    LEFT JOIN  pets        ON linkedTable = 'pets'        AND foreignId = pets.id
    LEFT JOIN  hobbies     ON linkedTable = 'hobbies'     AND foreignId = hobbies.id
    LEFT JOIN  sports      ON linkedTable = 'sports'      AND foreignId = sports.id
    LEFT JOIN  professions ON linkedTable = 'professions' AND foreignId = professions.id

C'est juste pour donner une plaisanterie de base. Étant donné que vous n'avez probablement besoin du lien que dans de rares cas, vous effectuerez probablement la recherche dans votre langage de programmation, comme PHP, lorsque vous parcourez les utilisateurs (sans jointure).

Vous voulez essayer ? Vous pouvez essayer vous-même en créant cette base de données de test (assurez-vous d'utiliser une base de données de test) :

CREATE TABLE IF NOT EXISTS `users` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `name` VARCHAR(100) NOT NULL , 
    `linkedTable` ENUM('pets','hobbies','sports','professions') NULL DEFAULT NULL , 
    `foreignId` INT NULL DEFAULT NULL , 
  PRIMARY KEY (`id`), INDEX (`linkedTable`)
) ;

CREATE TABLE  IF NOT EXISTS `pets` ( 
    `id` INT NOT NULL AUTO_INCREMENT , 
    `animalTypeId` INT NOT NULL , 
    `name` VARCHAR(100) NOT NULL , 
    `colorId` INT NOT NULL , 
  PRIMARY KEY (`id`), INDEX (`animalTypeId`), INDEX (`colorId`)
) ;

CREATE TABLE  IF NOT EXISTS `hobbies` ( 
    `id` INT NOT NULL AUTO_INCREMENT , 
    `hobbyTypeId` INT NOT NULL , 
    `hoursPerWeekSpend` INT NOT NULL , 
    `websiteUrl` VARCHAR(300) NULL , 
  PRIMARY KEY (`id`), INDEX (`hobbyTypeId`)
) ;

CREATE TABLE  IF NOT EXISTS `sports` ( 
    `id` INT NOT NULL AUTO_INCREMENT , 
    `sportTypeId` INT NOT NULL , 
    `hoursPerWeekSpend` INT NOT NULL , 
    `nameClub` VARCHAR(100) NULL , 
    `professional` TINYINT NOT NULL DEFAULT 0, 
  PRIMARY KEY (`id`), INDEX (`sportTypeId`)
) ;

CREATE TABLE  IF NOT EXISTS `professions` ( 
    `id` INT NOT NULL AUTO_INCREMENT , 
    `professionId` INT NOT NULL , 
    `hoursPerWeek` INT NOT NULL , 
    `nameCompany` VARCHAR(100) NULL , 
    `jobDescription` VARCHAR(400) NULL, 
  PRIMARY KEY (`id`), INDEX (`professionId`)
) ;


INSERT INTO `users` (`id`, `name`, `linkedTable`, `foreignId`) 
   VALUES 
   (NULL, 'Hank', 'pets', '1'), 
   (NULL, 'Peter', 'hobbies', '2'), 
   (NULL, 'Muhammed', 'professions', '1'), 
   (NULL, 'Clarice', NULL, NULL), 
   (NULL, 'Miryam', 'professions', '2'), 
   (NULL, 'Ming-Lee', 'hobbies', '1'), 
   (NULL, 'Drakan', NULL, NULL), 
   (NULL, 'Gertrude', 'sports', '2'), 
   (NULL, 'Mbase', NULL, NULL);


INSERT INTO `pets` (`id`, `animalTypeId`, `name`, `colorId`) 
VALUES (NULL, '1', 'Mimi', '3'), (NULL, '2', 'Tiger', '8');

INSERT INTO `hobbies` (`id`, `hobbyTypeId`, `hoursPerWeekSpend`, `websiteUrl`) 
VALUES (NULL, '123', '21', NULL), (NULL, '2', '1', 'http://www.freesoup.org');

INSERT INTO `sports` (`id`, `sportTypeId`, `hoursPerWeekSpend`, `nameClub`, `professional`) 
VALUES (NULL, '2', '3', 'Racket to Racket', '0'), (NULL, '12', '34', NULL, '1');

INSERT INTO `professions` (`id`, `professionId`, `hoursPerWeek`, `nameCompany`, `jobDescription`) 
VALUES (NULL, '275', '40', 'Ben & Jerry\'s', 'Ice cream designer'), (NULL, '21', '24', 'City of Dublin', 'Garbage collector');

Exécutez ensuite la première requête.

Note amusante pour la discussion :comment pourriez-vous vous indexer ça ?