sql >> Base de Datos >  >> RDS >> Mysql

MYSQL:una columna referenciada a varias tablas

Una respuesta muy tardía, pero para quien se esté preguntando y buscando en Google.

esto se puede hacer, pero NO es una buena práctica y, aunque es bastante simple, probablemente te explotará en la cara si no eres muy consciente de lo que estás haciendo. No recomendado.

Sin embargo, puedo ver usos. Por ejemplo, tiene una tabla grande de millones de registros y, en casos excepcionales, desea vincular tablas múltiples o desconocidas (en cuyo caso, es mejor que sean muchas). ). Con varias tablas, si creara una clave externa para todas ellas, eso sería una gran inflación en el tamaño de su base de datos. Una tabla desconocida sería posible, por ejemplo, en un sistema de soporte técnico, donde desea vincular para registrar en una tabla donde podría haber un problema, y ​​esto podría ser (casi) todas las tablas en la base de datos, incluidas las futuras.

Por supuesto, necesitarás dos campos con los que vincular:un campo de clave externa y el nombre de la tabla a la que se vincula. Llamémoslos foreignId y linkedTable

linkedTable podría ser una enumeración o una cadena, preferiblemente una enumeración (menos espacio), pero eso solo es posible si las diferentes tablas a las que desea vincularse están fijas.

Pongamos un ejemplo extremadamente tonto. Tienes una enorme tabla de usuarios users de los cuales algún usuario puede agregar exactamente uno conjunto personal de datos a su perfil. Esto puede ser sobre un pasatiempo, una mascota, un deporte que practican o su profesión. Ahora bien, esta información es diferente en los cuatro casos. (4 tablas posibles es en realidad no suficiente para justificar esta estructura)

Ahora digamos linkedTable es una enumeración con valores posibles pets , hobbies , sports y professions , que son los nombres de cuatro tablas estructuradas de forma diferente. Digamos id es la clave en los cuatro.

Te unes, por ejemplo, de la siguiente manera:

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

Esto es solo para dar una broma básica. Dado que probablemente solo necesite el enlace en casos excepcionales, es más probable que realice la búsqueda en su lenguaje de programación, como PHP, cuando recorra a los usuarios (sin unirse).

¿Quieres probar? Puede probarlo usted mismo creando esta base de datos de prueba (asegúrese de usar una base de datos de prueba):

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');

Luego ejecute la primera consulta.

Nota divertida para el debate:¿Cómo usted indexar esto?