sql >> Databáze >  >> RDS >> Mysql

MYSQL – jeden sloupec odkazovaný na vícenásobnou tabulku

Velmi pozdní odpověď, ale pro každého, kdo to zajímá a googluje.

ANO to lze provést, ale NE dobrá praxe a i když je to docela jednoduché, pravděpodobně vám to vybuchne do obličeje pokud si nejste příliš vědomi toho, co děláte. Nedoporučuje se.

Nicméně využití vidím. Máte například velkou tabulku s miliony záznamů a chcete ve výjimečných případech propojit s neznámými nebo více tabulkami (v takovém případě je lepší být mnoho ). Pokud byste s více tabulkami vytvořili cizí klíč pro všechny z nich, bylo by to obrovské nafouknutí ve velikosti vaší databáze. Neznámá tabulka by byla možná například v systému technické podpory, kde chcete odkazovat na záznam v tabulce, kde by mohl být problém, a to by mohly být (téměř) všechny tabulky v databázi, včetně budoucích.

Samozřejmě budete potřebovat dva pole k propojení:pole cizího klíče a název tabulky, na kterou se odkazuje. Říkejme jim foreignId a linkedTable

linkedTable může to být enum nebo řetězec, nejlépe enum (méně místa), ale to je možné pouze v případě, že různé tabulky, na které chcete odkazovat, jsou pevně dané.

Uveďme extrémně hloupý příklad. Máte obrovskou uživatelskou tabulku users z nichž některý uživatel může přidat právě jeden osobní soubor údajů do svého profilu. Může se jednat o koníčka, domácího mazlíčka, sport, který provozují nebo jejich povolání. Nyní se tato informace ve všech čtyřech případech liší. (4 možné tabulky ve skutečnosti není dostatečně ospravedlnit tuto strukturu)

Nyní řekněme linkedTable je výčet s možnými hodnotami pets , hobbies , sports a professions , což jsou názvy čtyř různě strukturovaných tabulek. Řekněme id je pkey ve všech čtyřech z nich.

Připojíte se například takto:

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

To je jen základní vtip. Vzhledem k tomu, že odkaz pravděpodobně potřebujete pouze ve vzácných případech, budete pravděpodobněji vyhledávat ve svém programovacím jazyce, jako je PHP, když procházíte uživatele (bez připojení).

Chcete vyzkoušet? Můžete to zkusit sami s vytvořením této testovací databáze (ujistěte se, že používáte testovací databázi):

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

Poté spusťte první dotaz.

Zábavná poznámka do diskuze:Jak byste vy indexovat to?



  1. Existuje nějaký způsob, jak zachytit chyby MySQL a databáze v PHP?

  2. Jak nahradit část řetězce v MySQL

  3. Jak vložit časové razítko do Oracle?

  4. získat tabulku JOIN jako pole výsledků s PostgreSQL/NodeJS