Bardzo późna odpowiedź, ale dla każdego, kto się zastanawia i googeluje.
TAK można to zrobić, ale NIE dobra praktyka i chociaż jest dość prosta, prawdopodobnie wybuchnie ci w twarz jeśli nie jesteś zbyt świadomy tego, co robisz. Niezalecane.
Widzę jednak zastosowania. Na przykład masz dużą tabelę zawierającą miliony rekordów i w wyjątkowych przypadkach potrzebujesz linku do nieznanych lub wielu tabel (wówczas lepiej jest wiele ). W przypadku wielu tabel, gdybyś utworzył klucz obcy dla nich wszystkich, byłby to ogromny rozrost w rozmiarze Twojej bazy danych. Nieznana tabela byłaby możliwa na przykład w systemie pomocy technicznej, gdzie chcesz połączyć się z rekordem w tabeli, w której może wystąpić problem, i mogą to być (prawie) wszystkie tabele w bazie danych, w tym przyszłe.
Oczywiście będziesz potrzebować dwóch pola do powiązania:pole klucza obcego i nazwa tabeli, do której się łączy. Nazwijmy je foreignId
i linkedTable
linkedTable
może być enum lub ciągiem, najlepiej enum (mniej miejsca), ale jest to możliwe tylko wtedy, gdy różne tabele, do których chcesz utworzyć link, są naprawione.
Podajmy wyjątkowo głupi przykład. Masz ogromną tabelę użytkowników users
z których niektórzy użytkownicy mogą dodać dokładnie jeden zestaw danych osobowych do swojego profilu. Może to dotyczyć hobby, zwierzaka, sportu, który uprawiają lub ich zawód. Teraz ta informacja jest inna we wszystkich czterech przypadkach. (4 możliwe tabele to w rzeczywistości nie wystarczy, aby uzasadnić tę strukturę)
Teraz powiedzmy, że linkedTable
to wyliczenie z możliwymi wartościami pets
, hobbies
, sports
i professions
, które są nazwami czterech tabel o różnej strukturze. Powiedzmy, że id
jest kluczem p we wszystkich czterech.
Dołączasz na przykład w następujący sposób:
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 tylko podstawowy żart. Ponieważ prawdopodobnie potrzebujesz linku tylko w rzadkich przypadkach, bardziej prawdopodobne jest, że wykonasz wyszukiwanie w swoim języku programowania, takim jak PHP, gdy przejdziesz przez użytkowników w pętli (bez dołączania).
Chcesz wypróbować? Możesz spróbować sam, budując tę testową bazę danych (upewnij się, że używasz testowej bazy danych):
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');
Następnie uruchom pierwsze zapytanie.
Zabawna uwaga do dyskusji:Jak byś Ty indeksować?