Một câu trả lời rất muộn, nhưng dành cho những ai đang thắc mắc &googeling.
CÓ điều này có thể được thực hiện, nhưng nó KHÔNG thực hành tốt và mặc dù nó khá đơn giản, nó có thể sẽ nổ tung vào mặt bạn nếu bạn không nhận thức rõ về những gì bạn đang làm. Không được khuyến khích.
Tuy nhiên, tôi có thể thấy công dụng. Ví dụ:bạn có một bảng lớn gồm hàng triệu bản ghi và bạn muốn trong các trường hợp ngoại lệ liên kết đến các bảng không xác định hoặc nhiều bảng (trong trường hợp đó tốt hơn là nhiều ). Với nhiều bảng, nếu bạn tạo một khóa ngoại cho tất cả chúng, điều đó sẽ là một khối lượng lớn về kích thước cơ sở dữ liệu của bạn. Ví dụ, một bảng không xác định sẽ có thể xảy ra trong hệ thống hỗ trợ kỹ thuật, nơi bạn muốn liên kết để ghi vào một bảng có thể có sự cố và đây có thể là (hầu hết) tất cả các bảng trong cơ sở dữ liệu, bao gồm cả những bảng trong tương lai.
Tất nhiên bạn sẽ cần hai các trường để liên kết với:trường khóa ngoại và tên của bảng mà nó đang liên kết đến. Hãy gọi chúng là foreignId
và linkedTable
linkedTable
có thể là một enum hoặc một chuỗi, tốt hơn là enum (ít khoảng trống hơn), nhưng điều đó chỉ có thể nếu các bảng khác nhau mà bạn muốn liên kết đến, được cố định.
Hãy đưa ra một ví dụ cực kỳ ngớ ngẩn. Bạn có một bảng người dùng khổng lồ users
trong đó một số người dùng có thể thêm chính xác một tập hợp dữ liệu cá nhân vào hồ sơ của họ. Đây có thể là về sở thích, thú cưng, môn thể thao mà họ luyện tập hoặc nghề nghiệp của họ. Bây giờ thông tin này là khác nhau trong cả bốn trường hợp. (4 bảng có thể có trong thực tế là không đủ để biện minh cho cấu trúc này)
Bây giờ, hãy nói linkedTable
là một enum với các giá trị có thể có pets
, hobbies
, sports
và professions
, là tên của bốn bảng có cấu trúc khác nhau. Giả sử id
là chìa khóa trong cả bốn người trong số họ.
Ví dụ, bạn tham gia như sau:
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
Đây chỉ là để đưa ra một trò đùa cơ bản. Vì bạn có thể chỉ cần liên kết trong một số trường hợp hiếm hoi, nên nhiều khả năng bạn sẽ thực hiện tra cứu bằng ngôn ngữ lập trình của mình, chẳng hạn như PHP, khi bạn lặp qua người dùng (không tham gia).
Bạn muốn chơi thử? Bạn có thể thử tự mình xây dựng cơ sở dữ liệu thử nghiệm này (đảm bảo bạn sử dụng cơ sở dữ liệu thử nghiệm):
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');
Sau đó, chạy truy vấn đầu tiên.
Ghi chú thú vị cho cuộc thảo luận:Làm thế nào bạn lập chỉ mục này?