Mysql
 sql >> Baza danych >  >> RDS >> Mysql

MYSQL — jedna kolumna odwołuje się do wielu tabel

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ć?



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. VARCHAR jako klucz obcy/klucz podstawowy w bazie danych dobry czy zły?

  2. Podczas uruchamiania UPDATE ... datetime =TERAZ(); czy wszystkie zaktualizowane wiersze będą miały tę samą datę/godzinę?

  3. Jak mogę wybrać sąsiedni wiersz w sql, gdy zamówię go według innego pola?

  4. MySQL:uporządkuj według wewnątrz grupy według

  5. Wstawianie rekordu do bazy danych MySQL za pomocą C#