数据库设计的递归关系
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库设计的递归关系相关的知识,希望对你有一定的参考价值。
考虑这种情况,我正在尝试为公司建模数据库:
- 实体:
Employees
,Managers
,Departments
。 Employee
仅在1个Department
工作,而Department
可能有许多Employees
工作。Manager
可能只管理1个Department
,同样Department
可能只有1个Manager
。- 一个
Manager
监督许多Employees
,但Employee
只受一个Manager
监督。
现在我有两种方法来模拟这个:
第一解决方案
我认为Manager
实体继承自Employee
实体,考虑到我将保留管理者独有的数据(例如奖金和状态)。
- 由于
Department
和Employee
之间的关系是1:N
然后我将Department Id
作为外键在Employee
表中为Works
关系。 - 由于
Department
和Manager
之间的关系是1:1
然后我将Department Id
作为外键在Manager
表中为Manages
关系。
问题:我如何表示Manager
和Employee
之间的递归关系?
二解决方案:
我认为不需要Manager
实体,因为其他Employees
也可能有Bonus
和Status
。 (实际上我添加了这两个属性只是为了看看如何在两种情况下对其进行建模)
- 由于
Department
和Employee
之间的关系是1:N
然后我将Department Id
作为外键在Employee
表中为Works
关系。 - 由于
Employee
和Manager
之间的关系是1:N
然后我将把Employee Id
作为Employee
关系的Supervises
表中的外键并称之为Manager Id
。
问题:我怎样才能代表Manager
和Department
之间的关系?
问题:
- 这两种设计都有明显的错误吗?
- 如何在两种情况下解决每个问题?
- 有没有比这两个更好的解决方案?
我可能会选择以下内容:
该模型具有以下特征:
- 经理“继承”员工。 要表示员工,请在EMPLOYEE中插入一行。 要表示经理,请在EMPLOYEE中插入一行,在MANAGER中插入一行。
- 一个部门可以拥有多名员工。
- 每个部门只有1个经理,每个经理管理0个或1个部门。
- 主管可以是普通员工或经理。
- 部门不需要“匹配”: 主管可以在受监督员工的不同部门工作。 经理可以管理他工作的不同部门。 如果主管是经理,那么他所管理的部门,他所在的部门以及他/她受监管的员工的部门都可以是不同的。
注意:如果您的DBMS不支持延迟约束,您将需要使DEPARTMENT.MANAGER_ID为NULL,以打破否则会阻止您插入新数据的循环。
如果要求部门匹配,那么您要么采用DBMS特定的技术(例如触发器或“特殊”约束),要么将DEPARTMENT_ID“传播”到员工的PK中。这种传播最终实现了匹配:
由于EMPLOYEE_ID必须是全局唯一的,因此它不能与DEPARTMENT_ID一起保留在组合键中。因此,我们将其替换为密钥,而是使用PK中的代理EMPLOYEE_NO。
此模型可以防止您拥有管理一个部门并在另一个部门工作的经理,或者监督来自不同部门的员工的主管。
如果你不熟悉这个符号......
......它表示“类别”。在这种情况下,您可以简单地将其解释为EMPLOYEE和MANAGER之间的“1到0或1”关系。
在没有详细说明的情况下,我确实向您保证,从长远来看,员工/经理/部门解决方案是一个不满(首先)然后是负责维护数据库和负责人的真正PITA(稍后)的来源。 /或开发其界面。所以我建议你坚持你的第二个提案。
关于经理/部门关系,您主要有两种方式来表示这种关系。两种解决方案都授权您保持递归“管理员管理员工”关系以及“经理管理部门”关系,您可以按如下方式实现:
1 - 第一种/简单方式:在部门表中添加经理/员工ID。该字段当然是employee表的外键
2秒/更复杂的解决方案:添加带有以下字段的“经理”表:
Manager id (PK, surrogate)
Department id (FK)
Employee id (FK)
beginningDate
endingDate
您将在哪里存储管理历史:谁,从哪个部门,从何时到何时
在这种情况下,不要忘记添加一些逻辑(触发器或客户端控制)来翻译您的业务规则,例如您可以在特定时间段和特定部门只有一个经理,没有任何部门可以留下超过......没有经理等
编辑:
3 - 更丰富的解决方案将是我的第二个提案的概括,并将允许您跟踪每个人在公司的职业生涯。你可以使用'works in'表格来完成它,例如这个(我们在这里称之为'position'表,我将在这里保留相同的术语:
Position id (PK, surrogate)
Department id (FK)
Employee id (FK)
Position Level (FK)
beginningDate
endingDate
“职位级别”导致另一个表格持有部门中可能存在的不同职位,其中一个当然是“经理人”职位。
此提议更接近人力资源数据库和软件中使用的提议,您可能不需要这么复杂的解决方案。但请记住,将人分成多个表总是一个错误。
编辑:关注你的评论......
为了清楚起见,我建议你调整你的字段名称。我建议您拥有以下字段:
Tbl_Employee.id_EmployeeManager
和
Tbl_Department.id_DepartmentManager
这样做,我们(或任何开发者)将立即理解id_EmployeeManager参与人之间的递归关系,而id_DepartmentManager参与人与部门之间的关系。
回到你的问题,根据我的说法,你不应该创建以下链接:
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_EmployeeManager
通过这样做,你意味着有人不能成为部门经理,除非他已经在管理员工。单个员工的部门怎么样?那些新成立的部门的管理人员怎么样呢,那里仍然没有分配员工?这是行不通的。正确的链接应该是:
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_Employee
您当然可以添加一些业务规则,例如“管理部门的员工只能是管理员”(id_Employee存在于某个地方作为id_EmployeeManager)或“管理部门的员工不能拥有管理员(此员工的id_EmployeeManager为null) ......)。但这些只是业务规则。只要基本规则得到尊重,您的数据模型就可以接受所有规则,即部门由员工管理!
我认为这是最好的解决方案:
经理是管理部门的员工。您可以通过下一个流程获得的递归关系:
员工有一个部门一个部门有一个员工作为经理
也许它可以为employee表提供一个EmployeeType列来定义角色。
我的看法:
表人员,你将为员工和经理添加信息,管理人员也是人,你知道吗? :),你有一个managerId字段链接到经理的Id。
表部门与部门信息
并且,如果员工可以属于多个部门,则创建一个表employee_department来关联它们。如果员工只能属于一个部门而您不需要关系中的更多信息,请在Employee表上添加departmentID字段。
如何坚持第二种设计并具有伪关系?
我假设你将在Employee实体中有一个department_id
列来链接Employee和Department实体之间的关系。如果我们可以假设不存在经理层级(经理的经理),我们可以在两个表之间强制执行伪关系,其中Department_ID
为经理(Manager_ID
为Null)代表他们管理的部门。
只要您清楚地记录这一点,我认为这将是一种节省空间的方法,因为您已经在引用Department实体的Employee实体中有一个FK列(department_id
)。
以上是关于数据库设计的递归关系的主要内容,如果未能解决你的问题,请参考以下文章