实体关系问题


19

我有4个与此相关的表(这是一个示例):

Company:
ID
Name
CNPJ

Department:
ID
Name
Code
ID_Company 

Classification:
ID
Name
Code
ID_Company

Workers:
Id 
Name
Code
ID_Classification
ID_Department

假设我有一个classificationid = 20, id_company = 1。并且department具有id_company = 2(代表另一家公司)。

这将允许创建来自两家公司的工人,因为分类和部门分别链接到该公司。我不希望这种情况发生,所以我认为我的人际关系存在问题,我不知道该如何解决。


1
什么是“分类”?
Jehad Keriaki 2015年

1
我想classification这类似于职位,即秘书,看门人,霸主等
。– Erik

您是否要强制工人必须与分类属于同一部门?
Lennart

也许部门,分类(甚至工人)应被视为薄弱的实体,所有这些都取决于公司。然后,公司密钥将成为部门,分类和工人密钥的一部分。一个弱实体是一个实体,其存在依赖于其他实体的存在。
miracle173

Answers:


9

您的问题源于模型中缺少实体类型的事实。考虑以下ERD:

ERD

请注意,我在和之间添加了交集实体类型。这种新的实体类型:提供模型中隐含的信息,即特定部门拥有一组不同分类的作业。DEPARTMENTCLASSIFICATIONPOSITION

POSITION作为显式实体添加到模型中有一些优点。

  1. 它避免了您担心WORKER可能会分配给不同公司的部门和分类的问题。
  2. 它为您提供了可能适用于该职位的其他谓词的位置,例如薪水等级等。
  3. 它允许您记录一个职位存在的事实,即使WORKER该职位当前没有,这也是很有用的信息。

请注意,为避免为不同公司的部门和分类定义职位的问题,我扩展了DEPARTMENT和的键CLASSIFICATION,这很好,因为您可以在Todd Everett的答案中详细阅读。

注意 上面的模型假定是一个简化。具体而言,假定每个位置仅记录一次。这可能适合或不适合您的业务规则。如果您需要POSITION公司中同一部门和分类的多个记录,则可以在中引入代理键POSITION


24

我认为您的关系没有问题。我认为问题在于,通过对每个表使用代理键(即Ids),结果数据库无法防止插入其部门属于一个公司而分类属于另一公司的工人,反之亦然。理解这一点的一种好方法是使用ER图表工具可视化架构。我将使用免费下载的Oracle Data Modeler工具。

ER图

在此处输入图片说明

就目前而言,您可能有两家公司-say IBMMicrosoftIBM可以有一个Software Development部门,而Microsoft可以有一个Desktop Software部门。IBM可以有一个Software Engineer分类,而Microsoft可以有一个Software Developer分类。现在,因为你有一个代理键DepartmentClassification,这其实Software Development是一个IBM部门,Desktop Software一个Microsoft部门失去了未来孩子的关系。的情况也是如此Classification。因此,很容易意外分配Harlan Mills,谁是部门的IBM雇员Software Development,其类别Software DeveloperMicrosoft分类!同样,可以给工人正确的分类和错误的部门!这是显示第一个示例的图:

在此处输入图片说明

1个ID代表IBM,而2个ID代表Microsoft。我已经以红色突出显示的场景Harlan MillsBill Gates被分配到错误的部门,由相关的200分类ID,反之亦然10部门ID显现。

解决方案

那么,有什么选择可以阻止他发生呢?有两个直接选择。首先是要认识到,通过为每个表使用代理键,此问题就存在了,并引入了其他编程来验证它不会发生。可以在应用程序中完成此操作,但是如果在应用程序外部可能发生插入和更新,则仍然可能发生错误的关联。更好的方法是创建一个在员工的插入和更新时触发的触发器,以确保指定部门与分配的类别属于同一公司,如果没有插入或更新,则触发该触发器。

第二种选择是不对每个表使用代理键。而是仅对Company基本表且没有父表的表使用代理键,然后创建与和子表的标识关系。现在,和表的PK 加上序号或名称以区分它们。然后,从关系和到也成为因此的PK 成为,再加上(我使用在该实例中的序列号),再加上。结果仅存在于表中。现在无法分配一个DepartmentClassificationDepartmentClassificationCompany IdDepartmentClassificationWorkeridentifyingWorkerCompany IdDepartment NumberClassification Numberone Company IdWorkerWorker一个Department在一个Company和一个Classification在另一个Company

为什么这不可能呢?这是不可能的,因为该模式实现之间的参照完整性WorkerDepartmentClassification。如果尝试在一个和另一个的Workera Department中插入a ,则对应的父表中不存在的组合将触发参照完整性违规,并且插入将不起作用。CompanyClassification

这是第二个选项的实现的更新图: 在此处输入图片说明

首选选项

在两个选项中,出于两个原因,我绝对更喜欢第二个选项-使用标识关系和级联键。首先,此选项无需其他编程即可实现所需的规则。开发触发器并非易事。必须对其进行编码,测试和维护。确保触发逻辑是最佳的,以免影响性能也不是一件容易的事。《数据库专业人员的应用数学》一书提供了有关这种解决方案的复杂性的许多详细信息。其次,这些规则暗示一个部门和一个分类不能在的上下文之外存在Company,因此该架构现在可以更准确地反映现实世界。

这是一个很好的问题,因为它确切地说明了为什么仅假设每个表都需要代理键是一个坏主意。 Fabian Pascal在此主题上有一篇出色的博客文章,表明从数据完整性的角度来看,代理键不仅是一个坏主意,而且还可能导致某些检索速度变慢在物理级别上,恰恰是因为不需要键,而键被正确地级联,就不需要连接。这个问题揭示的另一个有趣的话题是,数据库不能确保插入其中的所有数据相对于真实世界都是准确的。相反,它只能确保插入其中的数据与声明的规则一致。在这种情况下,我们可以通过使用级联键方法来确保 DBMS可以Worker就给定给定Companya的a Classification和给a Department相同的规则保持数据一致,从而做到最好Company。但是,如果在现实世界中Microsoft有一个部门被称为,Desktop Software但是数据库的用户断言该部门是Software Development DBMS只能做一个事实,它什么也不能做。


1

我理解问题的方式是,“工人”表的ID_Classification字段应仅允许为各个工人公司定义的分类。因此,验证(通过附加规则或通过TRIGGERS)插入/更新到Workers.ID_Classification字段中的信息足以满足此要求。


1

从我的阅读中,我仍然不了解这个分类是什么以及为什么它需要具有ID_Company。如果像这里提到的职位一样,我认为包含所有职位的静态表会更好。

如果这样做是为了轻松地找到公司中的分类/职位,请添加一个简单的查询/视图以连接分类工人-部门并检索分类的公司ID。

如今,存在更智能的视图或技术,例如物化视图和联接索引,因此,如果您的问题是查询的性能,请使用它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.