同僚はポリモーフィック団体と呼ばれるデザインを実現しました。つまり、「外部キー」は、2つの異なる親表のうちの1つを指します。ほとんどの人は別の列parent_type
などを追加して、特定の行がどの親テーブルに参照されているかを知ることができます。あなたの同僚の場合、彼は代わりにIDの範囲を細分しました。これはデータベースレベルでは実行できないため、脆弱な設計です。部門番号> 100を挿入すると、記事が部門または部門に適用されているかどうかを知ることができません。
Single Table Inheritanceのようなデザインを開発しましたが、複数の関連タイプを1つのテーブルに格納するので、主キーは一意のままであり、関連するタイプのインスタンスはすべて参照できます。
別の方法があります。
オブジェクト指向設計を考えてください。 2つの異なるクラスが記事を持つことを許可したい場合は、2つのクラスの共通のスーパークラスまたは共通のインターフェースを作成することができます。あなたは、SQLで同じことを行うことができます
ArticleProducer
---------------
ProducerID (PK) int NOT NULL
Department
----------
DepartmentID (PK) int NOT NULL, (FK)->ArticleProducer
DepartmentName varchar(50) NOT NULL
Division
--------
DivisionID (PK) int NOT NULL, (FK)->ArticleProducer
DepartmentID (FK) int NOT NULL
DivisonName varchar(50) NOT NULL
Article
-------
ArticleID (PK) int NOT NULL, (FK)->ArticleProducer
UniqueID int NOT NULL
ArticleName varchar(50) NOT NULL
ので記事は、単一のArticleProducer
によって生成されなければなりません。各部門または部門はArticleProducerです。
は私のプレゼンテーションPractical Object-Oriented Models in SQL、または私の本、SQL Antipatterns: Avoiding the Pitfalls of Database Programmingを参照してください、ポリモーフィック関連付けの詳細についてもWhy can you not have a foreign key in a polymorphic association?
を参照してください。すべてのサブタイプのテーブルからこれ以上より行は少しトリッキーであることを強制しようとして
そうだね、:
アーウィンSmoutから再コメント。残念ながら、MySQLはどのストレージエンジンでもCHECK制約をサポートしていません。
CREATE TABLE ArticleProducerTypes (ProducerType TINYINT UNSIGNED PRIMARY KEY);
INSERT INTO ArticleProducerTypes VALUES (1), (2);
CREATE TABLE ArticleProducer (
ProducerID INT UNSIGNED NOT NULL PRIMARY KEY,
ProducerType TINYINT UNSIGNED NOT NULL,
UNIQUE KEY (ProducerID,ProducerType),
FOREIGN KEY (ProducerType)
REFERENCES ArticleProducerTypes(ProducerType)
) ENGINE=InnoDB;
CREATE TABLE DepartmentProducerType (ProducerType TINYINT UNSIGNED PRIMARY KEY);
INSERT INTO DepartmentProducerType VALUES (1);
CREATE TABLE Department (
DepartmentID INT UNSIGNED NOT NULL PRIMARY KEY,
DepartmentName VARCHAR(50) NOT NULL,
ProducerType TINYINT UNSIGNED NOT NULL,
FOREIGN KEY (DepartmentID, ProducerType)
REFERENCES ArticleProducer(ProducerID, ProducerType),
FOREIGN KEY (ProducerType)
REFERENCES DepartmentProducerType(ProducerType) -- restricted to '1'
) ENGINE=InnODB;
CREATE TABLE DivisionProducerType (ProducerType TINYINT UNSIGNED PRIMARY KEY);
INSERT INTO DivisionProducerType VALUES (2);
CREATE TABLE Division (
DivisionID INT UNSIGNED NOT NULL PRIMARY KEY,
ProducerType TINYINT UNSIGNED NOT NULL,
DepartmentID INT UNSIGNED NOT NULL,
FOREIGN KEY (DivisionID, ProducerType)
REFERENCES ArticleProducer(ProducerID, ProducerType),
FOREIGN KEY (ProducerType)
REFERENCES DivisionProducerType(ProducerType), -- restricted to '2'
FOREIGN KEY (DepartmentID)
REFERENCES Department(DepartmentID)
) ENGINE=InnODB;
CREATE TABLE Article (
ArticleID INT UNSIGNED NOT NULL PRIMARY KEY,
ArticleName VARCHAR(50) NOT NULL,
FOREIGN KEY (ArticleID)
REFERENCES ArticleProducer(ProducerID)
);
ここで、ArticleProducerの各特定の行は、DepartmentまたはDivisionのいずれかで参照できますが、両方では参照できません。
新しいプロデューサ・タイプを追加する場合は、ArticleProducerTypes参照表に1行を追加し、新しいタイプの新しい表のペアを作成します。たとえば、次のように
INSERT INTO ArticleProducerTypes VALUES (3);
CREATE TABLE PartnerProducerType (ProducerType TINYINT UNSIGNED PRIMARY KEY);
INSERT INTO PartnerProducerType VALUES (3);
CREATE TABLE Partner (
PartnerID INT UNSIGNED NOT NULL PRIMARY KEY,
ProducerType TINYINT UNSIGNED NOT NULL,
FOREIGN KEY (PartnerID, ProducerType)
REFERENCES ArticleProducer(ProducerID, ProducerType),
FOREIGN KEY (ProducerType)
REFERENCES PartnerProducerType(ProducerType) -- restricted to '3'
) ENGINE=InnODB;
しかし、我々はまだどちらもArticleProducerでその特定の行への参照が含まれている可能性があります。つまり、従属テーブルの1つに行を強制的に作成するという制約を加えることはできません。私には解決策がありません。
以下に示す詳細、議論、および代替ソリューションを高く評価します。私は私の問題についての洞察を感じた答えをアップに投票しました。しかし、私は彼の答えが特定の質問に直接対処していると感じたので、私はDamirの答えを授与しました。 – NYSystemsAnalyst