Mysql
 sql >> Database >  >> RDS >> Mysql

MYSQL - Una colonna referenziata a più tabelle

Una risposta molto tardiva, ma per chi si chiede e googeling.

SI questo può essere fatto, ma NON buona pratica e anche se è abbastanza semplice, probabilmente ti esploderà in faccia se non sei molto consapevole di quello che stai facendo. Non consigliato.

Tuttavia, posso vedere gli usi. Ad esempio, hai una grande tabella di milioni di record e in casi eccezionali desideri collegare a tabelle sconosciute o multiple (in tal caso è meglio essere molte ). Con più tabelle, se dovessi creare una chiave esterna per tutte, sarebbe un enorme aumento delle dimensioni del tuo database. Una tabella sconosciuta sarebbe possibile, ad esempio, in un sistema di supporto tecnico, in cui si desidera collegarsi a un record in una tabella in cui potrebbe esserci un problema e questa potrebbe essere (quasi) tutte le tabelle nel database, comprese quelle future.

Ovviamente te ne serviranno due campi a cui collegarsi:un campo di chiave esterna e il nome della tabella a cui si sta collegando. Chiamiamoli foreignId e linkedTable

linkedTable potrebbe essere un enum o una stringa, preferibilmente enum (meno spazio), ma è possibile solo se le diverse tabelle a cui vuoi collegarti sono corrette.

Facciamo un esempio estremamente sciocco. Hai un'enorme tabella utenti users di cui alcuni utenti possono aggiungerne esattamente uno insieme di dati personali al proprio profilo. Può riguardare un hobby, un animale domestico, uno sport che praticano o la loro professione. Ora queste informazioni sono diverse in tutti e quattro i casi. (4 possibili tabelle in realtà non abbastanza per giustificare questa struttura)

Ora diciamo linkedTable è un enum con possibili valori pets , hobbies , sports e professions , che sono i nomi di quattro tabelle strutturate in modo diverso. Diciamo id è la pkey in tutti e quattro.

Ti iscrivi ad esempio come segue:

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

Questo è solo per dare una battuta di base. Dal momento che probabilmente il collegamento è necessario solo in rari casi, è più probabile che eseguirai la ricerca nel tuo linguaggio di programmazione, come PHP, quando esegui il ciclo degli utenti (senza partecipare).

Vuoi provare? Puoi provare tu stesso con la creazione di questo database di test (assicurati di utilizzare un database di 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');

Quindi esegui la prima query.

Nota divertente per la discussione:come vorresti tu indicizzare questo?