[英]Modeling a hierarchical data structure
假设我们有实体R,D和E,并且此关系基数
该规范的映射很简单,但是我们还有另一个要求:
附带条件:如果E1与某些D1相关并且此D1与R1相关,则E1可能仅被“分配”给R1。
不幸的是,即使E2与D2相关,而D2与R2相关-E2也可能与R2不相关。
一位朋友建议创建一个实体DxR,该实体通过元组(D,R)链接其D和R。 然后创建一个关系
嗯...
系统由顶层区域(Z)组成 。 一个区域可以具有多个区域(R) 。
所谓的部门(D)可以分配给区域 。 仅当每个部门属于不同的区域时,一个部门才能被分配到多个区域。
最后, 雇员(E)属于一个部门,并且只有一个部门 。
仅当员工部门属于该地区时,员工才能被分配到该地区。
重要提示: 员工不必属于其部门所属的所有区域。
假定在以下图形中E1属于D1。 E1也应该属于R1,但不属于R2-尽管D1属于R1和R2:
- Z Z
- __|___ ___|___
- R1 R R2 R
- \_________/
- D1
问:请提出对以上规范进行建模的关系数据库的表结构?
从某种意义上说,这个问题非常具体,有些人可能会认为它过于本地化。 但是,有一个更普遍适用的想法可能对将来的其他人有用,因此问题不一定太具体。
这些业务规则中真正有趣的部分是这一部分:( 我的重点是补充)
仅当每个部门属于不同的区域时,一个部门才能被分配到多个区域 。
这是一个模式,它以声明方式捕获了几乎所有陈述的业务规则,而不必诉诸任何触发器。
create table ZONE
( ID int not null
, NAME varchar(50) not null
, constraint PK_ZONE primary key clustered (ID)
)
create table REGION
( ZONE_ID int not null
, REGION_ID int not null
, NAME varchar(50) not null
, constraint PK_REGION primary key clustered (ZONE_ID, REGION_ID)
, conttraint FK_REGION__ZONE foreign key (ZONE_ID)
references ZONE (ID)
)
create table DEPARTMENT
( ID int not null
, NAME varchar(50) not null
, constraint PK_DEPARTMENT primary key clustered (ID)
)
create table EMPLOYEE
( ID int not null
, NAME varchar(50) not null
, DEPT_ID int not null
, constraint PK_EMPLOYEE primary key clustered (ID)
, constraint FK_EMPLOYEE__DEPARTMENT foreign key (DEPT_ID)
references DEPARTMENT (ID)
)
上表很明显。 但是,有一个特别的问题: REGION
表具有一个复合主键,其中包括FK到ZONE
。 这对于传播有关部门必须在区域内不同的约束很有用。
将部门分配到区域需要一个相交表:
create table DEPT_ASGT -- Department Assignment
( REGION_ID int not null
, DEPT_ID int not null
, ZONE_ID int not null
, constraint PK_DEPT_ASGT (REGION_ID, DEPT_ID)
, constraint FK_DEPT_ASGT__REGION foreign key (ZONE_ID, REGION_ID)
references REGION (ZONE_ID, ID)
, constraint FK_DEPT_ASGT__DEPARTMENT foreign key (DEPT_ID)
references DEPARTMENT (ID)
, constraint UN_DEPT_ASGT__ZONES unique nonclustered (ZONE_ID, DEPT_ID)
)
这个交集表是很正常的,因为它对它链接的每个表都有一个外键。 此交集表的特殊之处在于唯一性约束。 这就是强制执行以下规则的规定:部门不能位于同一区域内的两个不同区域中。
最后,我们需要将员工映射到部门和地区。 这需要另一个交集表:
create table EMP_ASGT -- Employee Assignment
( REGION_ID int not null
, DEPT_ID int not null
, EMPLOYEE_ID int not null
, constraint PK_EMP_ASGT (REGION_ID, DEPT_ID, EMPLOYEE_ID)
, constraint FK_EMP_ASGT__DEPT_ASGT (REGION_ID, DEPT_ID)
references DEPT_ASGT (REGION_ID, DEPT_ID)
, constraint FK_EMP_ASGT__EMPLOYEE (EMPLOYEE_ID) refernces EMPLOYEE (ID)
)
您将注意到EMPLOYEE
表具有DEPARTMENT
的外键-这将强制执行以下规则:每个员工只能属于一个部门。 EMP_ASGT
表添加有关员工参与的区域的详细信息。由于员工可能未参与其部门分配到的每个区域,因此EMP_ASGT
表将员工连接到他们所参与的那些区域。
这是需要触发器或其他一些过程逻辑的地方。 您需要确保EMPLOYEE.department_id与EMP_ASGT中的记录保持一致。 您可以通过将EMPLOYEE的PK设置为ID和DEPT_ID的组合,尝试将其推入声明性参照完整性,但这将迫使您决定是否要违反3NF或使员工部门更改为一个程序丑陋的混乱局面。 归根结底,只要稍加触发即可确保EMP_ASGT不反对EMPLOYEE.DEPT_ID,这将大大减少麻烦。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.