假设我们有实体R,D和E以及这种关系基数
此规范的映射是直截了当的,但我们还有另一项要求:
边条件:如果E1与某些D1相关且此D1与R1相关,则E1可能只会被“分配”到R1。
不幸的是,即使E2与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
问:请提出关系数据库的表格结构,该结构模拟上述规范?
答案 0 :(得分:1)
这个问题在某种意义上是非常具体的,有些人可能会认为它过于本地化。然而,还有一个更普遍适用的想法,可能对将来的其他人有用,所以问题太具体,这不一定是真的。
这些业务规则中真正有趣的部分是这个:(我的重点补充)
可能会将一个部门分配到多个区域,仅限于每个区域 区域属于不同的区域。
这是一个模式,可以声明性地捕获几乎所有已声明的业务规则,而不必诉诸任何触发器。
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的一点点触发器将不那么麻烦。