次の関係を表す3つのテーブル(パーティー、カテゴリーおよび製品)があります。
次に、パーティー関係があります:
つまり、製品にカテゴリを割り当てる必要はありませんが、製品にはそれぞれパーティを割り当てる必要があります。
カテゴリのparty_id
は、関連するために製品のparty_id
と一致する必要があります。
以下は、@ damir-sudarevicのソリューション提案に基づいた、上記のビジネスルールの修正です。
Category
はparty
によって定義されます。
category
は、1つのparty
によって定義されます。party
は複数のcategory
を定義する場合があります。Product
はparty
によって分類されます。
product
は、1つのparty
によって正確に分類されます。party
は複数のproduct
を分類する場合があります。Product
は、category
によってparty
に分類されます。
product
は、複数のcategory
に分類される場合があります。product
が同じcategory
に分類される場合があります。product
は、party
内のcategory
によって分類され、そのcategory
は、そのparty
によって定義されます。私が見つけた提案に基づいて最初のデザインを作成しました here ですが、製品とカテゴリーの両方にparty_id
を強制したいので、それは完全には適用できませんand関係で。
設計を多少簡略化する2番目の提案をしましたが、party_id
をProduct-Category関係に適用する方法がわかりません。
コメントとソリューションの提案に基づいて、テーブルとそれらの関係を作成するための簡略化されたSQLを追加しました。
CREATE TABLE IF NOT EXISTS parties (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id));
CREATE TABLE IF NOT EXISTS categories (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name_key VARCHAR(255) NOT NULL,
party_id INT(10) UNSIGNED NOT NULL,
parent_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id, party_id),
INDEX fk_categories_parent_category_idx (parent_id ASC),
UNIQUE INDEX name_key_UNIQUE (name_key ASC, party_id ASC),
INDEX fk_categories_party_idx (party_id ASC),
CONSTRAINT fk_categories_parent_category
FOREIGN KEY (parent_id)
REFERENCES categories (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_categories_party
FOREIGN KEY (party_id)
REFERENCES parties (id)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE IF NOT EXISTS products (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
party_id INT(10) UNSIGNED NOT NULL,
product_code VARCHAR(50) NOT NULL,
PRIMARY KEY (id, party_id),
UNIQUE INDEX product_code_UNIQUE (product_code ASC, party_id ASC),
INDEX fk_products_party_idx (party_id ASC),
CONSTRAINT fk_products_party
FOREIGN KEY (party_id)
REFERENCES parties (id)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE IF NOT EXISTS product_category (
product_id INT(10) UNSIGNED NOT NULL,
category_id INT(10) UNSIGNED NOT NULL,
party_id INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (product_id, category_id),
INDEX fk_product_category_product_idx (product_id ASC, party_id ASC),
INDEX fk_product_category_category_idx (category_id ASC, party_id ASC),
CONSTRAINT fk_product_category_product
FOREIGN KEY (product_id , party_id)
REFERENCES products (id , party_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT fk_product_category_category
FOREIGN KEY (category_id , party_id)
REFERENCES categories (id , party_id)
ON DELETE CASCADE
ON UPDATE CASCADE);
party_id
を適用せずに、アプリケーションレイヤーがproductをcategoryに割り当てるリスクを回避するために、3方向の関連付けテーブルを正しく設定するにはどうすればよいですか?
Category
のparty_id
は、関連付けるためにProduct
のparty_id
と一致する必要があります。
まあ、あなたの問題の表現によれば、Category
にparty_id
は必要ありません。
混乱はおそらく不正確な表現に起因し、述語と制約を1つの文にブレンドしています。
例えば:
- 製品は1対1のパーティーによって分類されます。
- パーティーは1対多の製品を分類します。
より明確に言い表すことができます:
Product
はparty
によって分類されます。product
は、1つのparty
によって分類されます。party
は複数のproduct
を分類する場合があります。この表現は、使用可能なモデルに直接つながります(述語、constraints)。
-- Party PTY exists.
--
party {PTY}
PK {PTY}
各製品は正確に1つのパーティによって分類されます。各パーティについて、そのパーティは複数の製品を分類する場合があります。
-- Product PRO, classified by party PTY exists.
--
product {PRO, PTY}
PK {PRO}
FK {PTY} REFERENCES party {PTY}
-- Category CAT exists.
--
category {CAT}
PK {CAT}
各製品について、その製品は複数のカテゴリーに分類される場合があります。各カテゴリーについて、複数の製品がそのカテゴリーに属するものとして分類される場合があります。
-- Product PRO is classified in category CAT.
--
product_category {PRO, CAT}
PK {PRO, CAT}
FK1 {PRO} REFERENCES product {PRO}
FK2 {CAT} REFERENCES category {CAT}
マッチングパーティーが知られる前に製品が知られている可能性があります。次にバリエーション:
-- Party PTY exists.
--
party {PTY}
PK {PTY}
-- Product PRO exists.
--
product {PRO}
PK {PRO}
-- Product PRO is classified by party PTY.
--
product_party {PRO, PTY}
PK {PRO}
FK1 {PRO} REFERENCES product {PRO}
FK2 {PTY} REFERENCES party {PTY}
-- Category CAT exists.
--
category {CAT}
PK {CAT}
-- Product PRO is classified in category CAT.
--
product_category {PRO, CAT}
PK {PRO, CAT}
FK1 {PRO} REFERENCES product_party {PRO}
FK2 {CAT} REFERENCES category {CAT}
いくつかのコメントの後:
Category
はparty
によって定義されます。
category
は1つのparty
によって定義されます。party
は複数のcategory
を定義する場合があります。Product
はparty
によって分類されます。
product
は、1つのparty
によって分類されます。party
は複数のproduct
を分類する場合があります。Product
はcategory
によってparty
に分類されます。
product
は複数のcategory
に分類される場合があります。product
が同じcategory
に分類される場合があります。product
がparty
のcategory
によって分類される場合、そのcategory
はそのparty
によって定義されます。Partyはcategoryおよびproductの前に存在する必要があります。
-- Party PTY exists.
--
party {PTY}
PK {PTY}
-- Product PRO, classified by party PTY exists.
--
product {PRO, PTY}
PK {PRO}
SK {PRO, PTY}
FK {PTY} REFERENCES party {PTY}
-- Category CAT, defined by party PTY exists.
--
category {CAT, PTY}
PK {CAT}
SK {CAT, PTY}
FK {PTY} REFERENCES party {PTY}
-- Product PRO is classified in category CAT
-- by party PTY.
--
product_category {PRO, CAT, PTY}
PK {PRO, CAT}
FK1 {PRO, PTY} REFERENCES product {PRO, PTY}
FK2 {CAT, PTY} REFERENCES category {CAT, PTY}
productとcategoryがpartyとは独立して存在できる場合。
-- Party PTY exists.
--
party {PTY}
PK {PTY}
-- Product PRO exists.
--
product {PRO}
PK {PRO}
-- Category CAT exists.
--
category {CAT}
PK {CAT}
-- Product PRO is classified by party PTY.
--
product_party {PRO, PTY}
PK {PRO}
SK {PRO, PTY}
FK1 {PRO} REFERENCES product {PRO}
FK2 {PTY} REFERENCES party {PTY}
-- Category CAT is defined by party PTY.
--
category_party {CAT, PTY}
PK {CAT}
SK {CAT, PTY}
FK1 {CAT} REFERENCES category {CAT}
FK2 {PTY} REFERENCES party {PTY}
-- Product PRO is classified in category CAT
-- by party PTY.
--
product_category {PRO, CAT, PTY}
PK {PRO, CAT}
FK1 {PRO, PTY} REFERENCES
product_party {PRO, PTY}
FK2 {CAT, PTY} REFERENCES
category_party {CAT, PTY}
注意:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
モデル#1を使用すると、データベース自体が指定された制約を強制するように作成できると信じています(つまり、categoryとproductは、両方が関連している場合にのみ関連している可能性があります同じparty)に次の制約を使用します。
product_partyのproduct_idには一意の制約があります。これにより、パーティーと製品の関係は、多対多ではなく1対多になります。これは次のことを意味します。
product_category_assignmentの主キーは、category_id、product_idおよびparty_idで構成されます。
ここでカバーされていない唯一の要件はproductがrequiredであることです関連パーティー(つまり、パーティーはオプションではありません)。
データベースのstructureで以下が許可されるため、モデル#2を使用すると、制約を適用するためにはるかに多くのコード(つまり、醜いストアドプロシージャ?)が必要になります。
上記の私の回答に若干の影響を与える可能性のあるいくつかの明記されていない要件があるように見えることを指摘しておきます。例えば...
私は常に、データモデルで重要な3つのことがあると述べてきました:詳細、DeTaiLsおよび[〜#〜]詳細[〜#〜]。場合によっては、複雑さに関するすべての関係の詳細を明らかにすることで、データモデルを設計する最良の方法を見つけることができます。このような複雑な関係は、欠落しているエンティティ(テーブル)を指す場合があります。複雑な要件は、データベースの構造的制約のみを使用して実施を無視し、ジョブを完了するために少しのコード(たとえば、ストアドプロシージャ?)を必要とする場合があります。
お役に立てば幸いです。