首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >递归关系的数据库设计

递归关系的数据库设计
EN

Stack Overflow用户
提问于 2012-04-02 03:34:14
回答 5查看 40.4K关注 0票数 21

考虑这样的情况,我试图为一家公司建模一个数据库:

  • Entities:EmployeesManagersDepartments.
  • An Employee仅在1个Department中工作,而一个Department可能有多个Employees在其中工作。D13可能仅管理1个D14,同样,D15可能只有1个

管理多个D20,但D21仅由一个Manager.管理

现在我有两种方法对此进行建模:

第一个解决方案:

考虑到我将保留经理唯一的数据(例如奖金和状态),我将考虑Manager实体继承自Employee实体。

  • 由于DepartmentEmployee之间的关系是1:N,因此我将把Department Id作为外键放在Employee表中用于Works关系。

  • 由于DepartmentManager之间的关系是1:1,因此我将把Department Id作为外键放在Manager表中用于Manages关系。

问题:如何表示Manager Employee**?**和之间的递归关系

第二种解决方案:

我将考虑不需要Manager实体,因为其他Employees可能也有BonusStatus。(实际上,我添加这两个属性只是为了看看如何在这两种情况下对其建模)

  • 由于DepartmentEmployee之间的关系是1:N,因此我将把Department Id作为外键放在Employee表中用于Works relation.
  • Since。Employee和D80之间的关系是D81,然后我将把D82作为外键放在D84关系的表中,并将其称为Manager Id.

问题:如何表示Manager Department**?**和之间的关系

问题:

  1. 这两种设计都有明显的错误吗?
  2. 如何解决这两种情况下的每个问题?
  3. 有比这两种更好的解决方案吗?
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-04-02 12:11:32

我可能会这样说:

该模型具有以下特点:

  • 管理器“继承”员工。
    • 要表示员工,请在employee中插入一行。
    • 要表示经理,请在EMPLOYEE 中插入一行,并在MANAGER.

中插入一行

employees.

  • Every

  • 一个部门可以有多个主管恰好有一个经理,每个经理管理0个或一个主管。主管可以是普通员工,也可以不要求主管“匹配”:
  • 主管可以在与被主管员工不同的部门工作。
  • 经理可以从他工作的地方管理不同的部门。
  • 如果主管是经理,则他管理的部门。
  • 他所在的部门和他/她所管理的员工的部门都可以是different.

注意:如果您的数据库管理系统不支持延迟约束,您将需要使DEPARTMENT.MANAGER_ID可以为空,以打破否则将阻止您插入新数据的循环。

如果需要匹配部门,那么您可以使用特定于DBMS的技术(例如触发器或“特殊”约束),或者将DEPARTMENT_ID“传播”到员工的PK中。这种传播最终实现了匹配:

由于EMPLOYEE_ID必须是全局唯一的,所以它不能和DEPARTMENT_ID一起留在组合键中。因此,我们将其设置为alternate key,并在PK中使用代理EMPLOYEE_NO。

此模型可防止经理管理一个部门并在另一个部门工作,或主管管理来自不同部门的员工。

如果你不熟悉这个符号..。

...it表示一个“类别”。在这种情况下,您可以简单地将其解释为员工和经理之间的"1对0或1“关系。

票数 28
EN

Stack Overflow用户

发布于 2012-04-02 20:27:37

我向您保证,从长远来看,员工/经理/部门解决方案对于负责维护数据库和/或开发其界面的人员来说,首先是一个令人不快的来源,然后是一个真正的PITA (后来)。所以我建议你坚持你的第二个建议。

对于经理/部门关系,您主要有两种方式来表示这种关系。这两种解决方案都授权您保留递归的"Manager manages Employee“关系,以及您可以实现的"manager manages Department”关系,如下所示:

1-第一种/简单的方法:在部门表中添加经理/员工id。此字段当然是employee表的外键

2秒/更复杂的解决方案:添加一个包含以下字段的"manager“表:

代码语言:javascript
运行
复制
Manager id (PK, surrogate)
Department id (FK)
Employee id (FK)
beginningDate
endingDate

您将在何处存储管理历史:谁、为哪个部门、从何时到何时

在这种情况下,不要忘记添加一些逻辑(触发器或客户端控制)来转换您的业务规则,例如,对于特定的期间和特定的部门,您只能有一个经理,任何部门都不能超过...没有经理,等等。

编辑:

3-一个更丰富的解决方案将是我的第二个建议的概括,并将允许您跟踪每个人在公司的职业生涯。你可以用一个'works in‘表来实现,比如这个(我们在这里叫它'position’表,这里我将保留相同的术语:

代码语言:javascript
运行
复制
Position id (PK, surrogate)
Department id (FK)
Employee id (FK)
Position Level (FK)
beginningDate
endingDate

其中'position level‘通向另一个表,其中包含一个部门中可能存在的不同职位,其中一个当然是’经理‘职位。

此建议更接近HR数据库和软件中使用的内容,您可能不需要如此复杂的解决方案。但请记住,将人类划分到多个表中始终是错误的。

编辑:关注您的评论...

为了清楚起见,我建议您调整您的字段名称。我建议你有以下几个领域:

代码语言:javascript
运行
复制
Tbl_Employee.id_EmployeeManager

代码语言:javascript
运行
复制
Tbl_Department.id_DepartmentManager

这样做,我们(或任何开发人员)将立即理解,id_EmployeeManager参与人员之间的递归关系,而id_DepartmentManager参与人员与部门之间的关系。

回到你的问题,根据我的说法,你不应该创建以下链接:

代码语言:javascript
运行
复制
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_EmployeeManager

这样做,你的意思是,除非某人已经在管理员工,否则不能成为部门经理。如果部门只有一名员工呢?如果被指定为新创建的部门经理的人员仍然没有分配员工,该怎么办?它不起作用。正确的链接应该是:

代码语言:javascript
运行
复制
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_Employee

当然,您可以添加一些业务规则,例如“管理部门的员工只能是经理”(id_Employee在某处以id_EmployeeManager的形式存在)或“管理部门的员工不能有经理(该员工的id_EmployeeManager为null...)。但这些只是业务规则。只要遵守基本规则,您的数据模型就可以接受所有规则,即部门由员工管理!”

票数 1
EN

Stack Overflow用户

发布于 2012-04-02 03:39:55

我的观点是:

表Person,您将在其中添加员工和经理的信息,经理也是人,您知道吗?:),并且您有一个链接到经理Id的managerId字段。

表department包含部门信息

而且,如果员工可以属于多个部门,则创建一个表employee_department来关联它们。如果一个员工只能属于一个部门,并且您不需要关系中的更多信息,那么在employee表上添加一个departmentID字段。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9967602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档