我在为基于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图。并且感谢您的帮助。
以下是一些示例数据
答案 0 :(得分:2)
正如我所看到的,您的设计的核心问题是使用代理键。 没有必要始终为表创建数字单列键。 即使你这样做,这并不能保证你没有重复。 事实上,这迫使系统在表上保留更多索引,这就是 一项额外的工作要做。
一些概念:
<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的未来版本中产生意想不到的影响。
答案 1 :(得分:1)
DB Design完全没问题。
只需使用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;