[英]join between two many-to-many tables
我在為基於java的Web應用程序定義適當的數據庫設計時遇到一些麻煩。 我有3個表(Tag,DT和Property),我的場景如下。 每個標簽可以包含許多Dts,每個DT可以分配給不同的標簽,每個DT都有許多屬性,每個屬性可以在許多DT中使用。 將DT分配給Tag時,用戶可以為其所有屬性設置值。
我的問題是如何定義一個關系,使得每個Tag的屬性值可以基於分配給它的DT。 在我的設計中缺少什么表和關系。 我必須根據此db創建相對實體。
Tag1==> DT1 ==> Initial values1, property values set 1 ;
Tag2==> DT1 ==> Initial values1, property values set 2 ;
這是db圖。 並提前感謝您的幫助。
這是一些示例數據
正如我所看到的,您的設計的核心問題是使用代理鍵。 沒有必要始終為表創建數字單列鍵。 即使你這樣做,這並不能保證你沒有重復。 事實上,這迫使系統在表上保留更多索引,這是一項額外的工作。
一些概念:
<table_name>_id
用於PK列。 由於單個表名,它也是可能的; 您不必遵循它們,但堅持設計的一致命名模式是非常好的。
我將從property_type
字典開始:
CREATE TABLE property_type ( property_type varchar(20) NOT NULL, CONSTRAINT p_property_type PRIMARY KEY (property_type) );
它是一個單列表,僅用於為屬性類型提供可能值的域。 我使用varchar(20)
,文本列很精細。 這樣做的好處是 - 您不必通過數字鍵連接回此表以獲取property_type_id=123
含義。
屬性:
CREATE TABLE property ( property_id integer NOT NULL, property_name varchar(50) NOT NULL, property_type varchar(20) NOT NULL, CONSTRAINT p_property PRIMARY KEY (property_id), CONSTRAINT u_property_name UNIQUE (property_name), CONSTRAINT f_property_type FOREIGN KEY (property_type) REFERENCES property_type ON UPDATE CASCADE );
我決定在這里使用數字PK,因為我想你可能想在某個時候重命名屬性。 如果您更改property_type
,則會更新級別更新。
盡管這里已經存在PK,但是對於名稱的UNIQUE
約束是必須的,否則您可能會遇到具有不同ID的同等命名屬性的情況。
DT表:
CREATE TABLE dt ( dt_id integer NOT NULL, dt_name varchar(50) NOT NULL, CONSTRAINT p_dt PRIMARY KEY (dt_id), CONSTRAINT u_dt_name UNIQUE (dt_name) );
再說一次,僅僅PK還不夠,還要創建UNIQUE
約束。 雖然我會完全擺脫dt_id
並且只保留dt_name
並且會使它成為PK。
DT的屬性:
CREATE TABLE dt_property ( dt_id integer NOT NULL, property_id integer NOT NULL, initial_value varchar(50) NOT NULL, CONSTRAINT p_dt_property PRIMARY KEY (dt_id, property_id), CONSTRAINT f_dt_id FOREIGN KEY (dt_id) REFERENCES dt, CONSTRAINT f_property_id FOREIGN KEY (property_id) REFERENCES property );
這是與您的設計的第一個重大區別 - 使用了復合鍵。
是的,這意味着只要您想參考此表中的條目,就必須執行2列。 但這不是什么大問題,真的 - 你設計一次表,你也只寫一次你的查詢,但是你的軟件可能會被使用很長時間,如果它已經完成並且容易維護。 最好花一點時間編寫查詢並從長遠來看容易維護的系統。
標簽:
CREATE TABLE tag ( tag_id integer NOT NULL, tag_name varchar(50) NOT NULL, CONSTRAINT p_tag PRIMARY KEY (tag_id), CONSTRAINT u_tag_name UNIQUE (tag_name) );
這只是另一本字典。 同樣,像dt
表,我真的想避免使用tag_id
列,只保留tag_name
,使得它也是一個PK。
新表tag_dt
介紹:
CREATE TABLE tag_dt ( tag_id integer NOT NULL, dt_id integer NOT NULL, CONSTRAINT p_tag_dt PRIMARY KEY (tag_id, dt_id), CONSTRAINT f_tag_id FOREIGN KEY (tag_id) REFERENCES tag, CONSTRAINT f_dt_id FOREIGN KEY (dt_id) REFERENCES dt );
此表是創建dt
+ tag
關系所必需的。 沒有它,你有數據重復 - 你可以在你的架構上看到它,你有2行Tag_name='Tag1'
。
最后,標簽屬性:
CREATE TABLE tag_property ( tag_id integer NOT NULL, dt_id integer NOT NULL, property_id integer NOT NULL, a_value varchar(50) NOT NULL, CONSTRAINT p_tag_property PRIMARY KEY (tag_id, dt_id), CONSTRAINT u_tag_property UNIQUE (tag_id, property_id), CONSTRAINT f_tag_property_tag FOREIGN KEY (tag_id, dt_id) REFERENCES tag_dt, CONSTRAINT f_tag_property_property FOREIGN KEY (dt_id, property_id) REFERENCES dt_property );
此表是完整的復合鍵,它符合您的所有要求。 主鍵是tag_id, dt_id
,它也是tag_dt
表的外鍵,因此您希望能夠引入之前未定義的內容。 接下來, tag_id, property_id
是唯一的,這意味着標簽的屬性不能復制。 最后, dt_id, property_id
引用dt_property
表,這意味着只會注冊該dt
允許的屬性。
所有主鍵和唯一鍵都是通過大多數DBMS中的索引實現的。 此外,即使省略了鍵的第一列,某些DBMS也可以使用復合索引(多列索引)。 至少PostgreSQL可以做到這一點,這是我最常用的。
請查看你的dt
和tag
表,我強烈建議去掉那些代理鍵,就像property_type
完成一樣。
我沒有創建任何額外的索引,通常我會在實現數據模型之后執行此練習並對其進行一些實際查詢。
另外,不要使用value
或name
的列名。 這些是保留字,您可能會在您選擇的DBMS的未來版本中產生意想不到的影響。
數據庫設計完全沒問題。
只需使用Tag_DT和DT_Property表
以下是示例查詢
select a.id_tag,b.id_Property
from
tag_dt a,dt_property b
where a.id_dt = b.id_dt;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.