簡體   English   中英

在兩個多對多表之間連接

[英]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圖。 並提前感謝您的幫助。

在此輸入圖像描述

這是一些示例數據

在此輸入圖像描述

正如我所看到的,您的設計的核心問題是使用代理鍵。 沒有必要始終為表創建數字單列鍵。 即使你這樣做,這並不能保證你沒有重復。 事實上,這迫使系統在表上保留更多索引,這是一項額外的工作。

  1. 一些概念:

    • 我使用單數作為表名,'cos表中的每個元組代表關系的一個對象;
    • 我使用小寫字母表和列名(標識符)和大字母作為關鍵字。 我不喜歡數據庫中的CamelCase;
    • 我將<table_name>_id用於PK列。 由於單個表名,它也是可能的;
    • 我為我創建的所有約束和索引使用前綴+表名+詳細信息。

    您不必遵循它們,但堅持設計的一致命名模式是非常好的。

  2. 我將從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含義。

  3. 屬性:

     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的同等命名屬性的情況。

  4. 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。

  5. 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列。 但這不是什么大問題,真的 - 你設計一次表,你也只寫一次你的查詢,但是你的軟件可能會被使用很長時間,如果它已經完成並且容易維護。 最好花一點時間編寫查詢並從長遠來看容易維護的系統。

  6. 標簽:

     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。

  7. 新表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'

  8. 最后,標簽屬性:

     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可以做到這一點,這是我最常用的。

請查看你的dttag表,我強烈建議去掉那些代理鍵,就像property_type完成一樣。

我沒有創建任何額外的索引,通常我會在實現數據模型之后執行此練習並對其進行一些實際查詢。

另外,不要使用valuename的列名。 這些是保留字,您可能會在您選擇的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM