5

テーブル内の 1 つの列を複数のテーブルから参照できますか?

4

4 に答える 4

7

非常に遅い答えですが、疑問に思っている人やグーグルで調べている人向けです。

はい、これを行うことはできますが、良い習慣ではありません。非常に単純ですが、自分が何をしているのかをよく認識していないと、おそらく顔が爆発するでしょう。推奨されません。

しかし、私は用途を見ることができます。たとえば、何百万ものレコードからなる大きなテーブルがあり、例外的に、不明なテーブルまたは複数のテーブルにリンクする必要があるとします (この場合は、多くする方がよい)。複数のテーブルがある場合、それらすべてに対して外部キーを作成すると、データベースのサイズが非常に大きくなります。不明なテーブルは、たとえばテクニカル サポート システムで、問題がある可能性があるテーブルのレコードにリンクする場合に発生する可能性があります。これは、将来のテーブルを含め、データベース内の (ほぼ) すべてのテーブルである可能性があります。

もちろん、リンクするには2 つのフィールドが必要です。外部キー フィールドと、リンク先のテーブルの名前です。それらforeignIdを呼び出してみましょうlinkedTable

linkedTable列挙型または文字列、できれば列挙型 (スペースが少ない) にすることができますが、リンク先の異なるテーブルが固定されている場合にのみ可能です。

非常にばかげた例を挙げましょう。膨大な数のユーザー テーブルがあり、そのうちの一部のユーザーは、個人データのセットを1 つだけプロファイルにusers追加できます。これは、趣味、ペット、練習しているスポーツ、または職業に関するものです。現在、この情報は 4 つのケースすべてで異なります。(4 つの可能なテーブルは、実際にはこの構造を正当化するのに十分ではありません)

ここで、 、、およびのlinkedTable可能な値を持つ列挙型であるとしましょう。これらは、4 つの異なる構造のテーブルの名前です。4つすべてのpkeyであるとしましょう。petshobbiessportsprofessionsid

たとえば、次のように参加します。

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

これは基本的な冗談を言うためのものです。リンクが必要になるのはまれなケースだけなので、ユーザーを (結合せずに) ループするときは、PHP などのプログラミング言語でルックアップを行う可能性が高くなります。

試してみませんか?このテスト データベースを構築して、自分で試すことができます (必ずテスト データベースを使用してください)。

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

次に、最初のクエリを実行します。

議論のための楽しいメモ: これをどのよう索引付けしますか?

于 2018-07-15T15:17:39.467 に答える
0

はい、そうすることができます。これを行う方法のサンプルを次に示します。

複数のテーブルによって参照される列 (CountryID) を持つテーブルを次に示します。

CREATE TABLE DLAccountingSystem.tblCountry
(
    CountryID       INT             AUTO_INCREMENT NOT NULL PRIMARY KEY,
    CountryName     VARCHAR(128)    NOT NULL,
    LastEditUser    VARCHAR(128)    NOT NULL,
    LastEditDate    DATETIME        NOT NULL
) ENGINE=INNODB;

列 (CountryID) を参照するテーブルは次のとおりです。

CREATE TABLE DLAccountingSystem.tblCity
(
    CityID          INT             AUTO_INCREMENT NOT NULL PRIMARY KEY,
    CountryID       INT             NOT NULL,
    CityName        VARCHAR(128)    NOT NULL,
    LastEditUser    VARCHAR(128)    NOT NULL,
    LastEditDate    DATETIME        NOT NULL
) ENGINE=INNODB;

CREATE TABLE DLAccountingSystem.tblProvince
(
    ProvinceID      INT             AUTO_INCREMENT NOT NULL PRIMARY KEY,
    CountryID       INT             NOT NULL,
    ProvinceName    VARCHAR(128)    NOT NULL,
    LastEditUser    VARCHAR(128)    NOT NULL,
    LastEditDate    DATETIME        NOT NULL
) ENGINE=INNODB;

列への参照を作成する方法は次のとおりです。

 ALTER TABLE DLAccountingSystem.tblCity
 ADD CONSTRAINT fk_tblcitycountryid FOREIGN KEY CountryID (CountryID)
 REFERENCES DLAccountingSystem.tblCountry (CountryID)
 ON DELETE NO ACTION
 ON UPDATE NO ACTION

 ALTER TABLE DLAccountingSystem.tblProvince
 ADD CONSTRAINT fk_tblprovincecountryid FOREIGN KEY CountryID (CountryID)
 REFERENCES DLAccountingSystem.tblCountry (CountryID)
 ON DELETE NO ACTION
 ON UPDATE NO ACTION

これは、(CountryID、ProvinceID、CityID)複数のテーブルからの異なる列を参照する列を持つテーブルです(私はこの方法でテーブルを構造化することを個人的にアドバイスしません.私の意見は不快ではありません;))

CREATE TABLE DLAccountingSystem.tblPersons
(
    PersonID       INT          AUTO_INCREMENT NOT NULL PRIMARY KEY,
    PlaceID        INT          NOT NULL,
    PlaceTypeID    INT          NOT NULL, -- this property refers to what table are you referencing.
 //Other properties here.....
) ENGINE=INNODB;

PlaceType を含むルックアップ テーブルも必要です。

CREATE TABLE DLAccountingSystem.tblPlaceType
(
    PlaceTypeID       INT          AUTO_INCREMENT NOT NULL PRIMARY KEY,
    PlaceTypeName        INT          NOT NULL
 //Other properties here.....
) ENGINE=INNODB;

これを取得する方法は次のとおりです。

SELECT p1.PersonID,
       tcity.CityName,
       tprov.ProvinceName,
       tcoun.CountryName
FROM DLAccountingSystem.tblPersons p1 
LEFT JOIN (SELECT p2.PersonID, p2.PlaceTypeID, c.CityName FROM DLAccountingSystem.tblPersons p2 INNER JOIN DLAccountingSystem.tblCity c ON p2.ObjectID = c.CityID WHERE PlaceTypeID = @CityTypeID) tcity ON p1.PersonID = tcity.PersonID
LEFT JOIN (SELECT p2.PersonID, p2.PlaceTypeID, c.ProvinceName FROM DLAccountingSystem.tblPersons p2 INNER JOIN DLAccountingSystem.tblProvince c ON p2.ObjectID = c.ProvinceID WHERE PlaceTypeID = @ProvinceTypeID) tprov ON p1.PersonID = tprov.PersonID
LEFT JOIN (SELECT p2.PersonID, p2.PlaceTypeID, c.CountryName FROM DLAccountingSystem.tblPersons p2 INNER JOIN DLAccountingSystem.tblCountry c ON p2.ObjectID = c.CountryID WHERE PlaceTypeID = @CountryTypeID) tcoun ON p1.PersonID = tcoun.PersonID

次のような他のテーブルから選択できます

于 2012-06-01T03:18:01.723 に答える
0

「1 つのテーブルの列を複数のテーブルの外部キーとして使用できる」という意味であれば、答えはYESです。これがリレーショナル データベースの要点です

于 2012-06-01T03:07:34.137 に答える