Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MYSQL - Uma coluna referenciada a várias tabelas


Uma resposta muito tardia, mas para quem está se perguntando e pesquisando no Google.

SIM isso pode ser feito, mas NÃO boa prática e mesmo sendo bem simples, provavelmente explodirá na sua cara se você não estiver muito consciente do que está fazendo. Não recomendado.

No entanto, eu posso ver usos. Por exemplo, você tem uma grande tabela de milhões de registros e deseja, em casos excepcionais, vincular a tabelas desconhecidas ou múltiplas (nesse caso, é melhor que sejam muitos ). Com várias tabelas, se você criasse uma chave estrangeira para todas elas, isso seria um enorme inchaço no tamanho do seu banco de dados. Uma tabela desconhecida seria possível, por exemplo, em um sistema de suporte técnico, onde você deseja vincular o registro em uma tabela onde pode haver um problema, e isso pode ser (quase) todas as tabelas do banco de dados, incluindo as futuras.

Claro que você precisará de dois campos para vincular:um campo de chave estrangeira e o nome da tabela à qual está vinculando. Vamos chamá-los de foreignId e linkedTable

linkedTable pode ser um enum ou uma string, de preferência enum (menos espaço), mas isso só é possível se as diferentes tabelas às quais você deseja vincular forem fixas.

Vamos dar um exemplo extremamente bobo. Você tem uma enorme tabela de usuários users dos quais alguns usuários podem adicionar exatamente um conjunto pessoal de dados ao seu perfil. Isso pode ser sobre um hobby, um animal de estimação, um esporte que eles praticam ou sua profissão. Agora esta informação é diferente em todos os quatro casos. (4 tabelas possíveis na realidade não suficiente para justificar esta estrutura)

Agora vamos dizer linkedTable é uma enumeração com valores possíveis pets , hobbies , sports e professions , que são os nomes de quatro tabelas estruturadas de forma diferente. Digamos id é o pkey em todos os quatro deles.

Você se junta, por exemplo, da seguinte forma:
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

Isso é só para dar uma brincadeira básica. Como você provavelmente só precisa do link em casos raros, é mais provável que você faça a pesquisa em sua linguagem de programação, como PHP, quando percorrer os usuários (sem junção).

Quer experimentar? Você pode tentar você mesmo construindo este banco de dados de teste (certifique-se de usar um banco de dados de teste):
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');

Em seguida, execute a primeira consulta.

Nota divertida para discussão:Como você indexar isso?