Luc*_*ini 18 database-design constraint
我有 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
Run Code Online (Sandbox Code Playgroud)
假设我有一个classificationwith id = 20, id_company = 1。并且department有id_company = 2(代表另一家公司)。
这将允许创建来自两个公司的工人,因为分类和部门分别链接到公司。我不希望这种情况发生,所以我认为我的人际关系有问题,我不知道如何解决。
Tod*_*ett 26
我认为你的人际关系没有问题。我认为问题在于,通过为每个表使用代理键(即 Id),生成的数据库无法阻止插入部门属于一个公司而分类属于另一个公司的工人,反之亦然。理解这一点的一个好方法是使用 ER 图表工具将模式可视化。我将使用免费下载的Oracle Data Modeler工具。
就目前而言,您可以拥有 2 家公司——比如说IBM和Microsoft。 IBM可以有一个Software Development部门,微软也可以有一个Desktop Software部门。IBM 可以有一个Software Engineer分类,Microsoft 可以有一个Software Developer分类。现在,因为你有一个代理键Department和Classification,这其实Software Development是一个IBM部门,Desktop Software一个Microsoft部门失去了未来孩子的关系。情况也是如此Classification。因此,很容易不小心分配Harlan Mills,谁是部门的IBM员工Software Development,一个分类Software Developer是Microsoft分类!同样,工人可能会被赋予正确的分类和错误的部门!这是显示第一个示例的图表:
1 个 Id 代表IBM,2 个 Id 代表Microsoft。我用红色突出显示了Harlan Mills和Bill Gates被分配到错误部门的场景,这通过与 200 个分类 ID 关联的 10 个部门 ID 进行可视化,反之亦然。
那么有什么办法可以防止他的发生呢?有两个直接选择。第一个是意识到通过为每个表使用代理键这个问题存在,并引入额外的编程来验证它不会发生。这可以在应用程序中完成,但如果插入和更新可以在应用程序之外发生,那么不正确的关联仍然可能发生。更好的方法是创建一个触发器,在插入和更新员工时触发,以确保分配的部门与分配的分类属于同一公司,如果没有失败,则插入或更新。
第二种选择是不对每个表使用代理键。相反,仅对Company表使用代理键,这是基本的并且没有父表,然后创建与子表和子表的标识关系。在和表格现在的一个PK加了序列号或名称来区分它们。然后,from和to的关系也变成了,因此 PK变成了,加上了(我在这个例子中使用了一个序列号),加上. 结果是只有在表中。现在无法分配DepartmentClassificationDepartmentClassificationCompany IdDepartmentClassificationWorkeridentifyingWorkerCompany IdDepartment NumberClassification Numberone Company IdWorkerWorker一个Department在一个Company和一个Classification在另一个Company。
为什么这是不可能的?这是不可能的,因为该模式实现之间的参照完整性Worker和Department和Classification。如果尝试在一个和另一个中插入一个Workerfor a Department,则相应父表中不存在的组合将触发参照完整性违规,并且插入将不起作用。CompanyClassification
在这两个选项中,我绝对更喜欢第二个 - 使用识别关系和级联键 - 有两个原因。首先,此选项无需额外编程即可实现所需规则。开发触发器并非易事。它必须被编码、测试和维护。确保触发逻辑是最佳的,以免影响性能也并非易事。《数据库专业人员应用数学》一书详细介绍了这种解决方案的复杂性。其次,规则意味着部门和分类不能存在于 的上下文之外Company,因此模式现在更准确地反映了现实世界。
这是一个很好的问题,因为它确切地说明了为什么简单地假设每个表都需要一个代理键是一个坏主意。 Fabian Pascal有一篇关于这个主题的优秀博客文章表明,从数据完整性的角度来看,代理键不仅可能是一个坏主意,它还可能导致某些检索变慢在物理级别,正是因为需要连接,如果键正确级联,则不需要。这个问题揭示的另一个有趣的话题是,数据库无法确保插入其中的所有数据对于现实世界都是准确的。相反,它只能确保插入其中的数据与向其声明的规则一致。在这种情况下,我们可以通过使用级联键方法来尽可能做到最好,以但数据库的用户断言该部门是确保DBMS 可以保持数据与Worker给定的 aCompany需要分配给定的aClassification和Department相同的a的规则一致Company。但是,如果在现实世界中Microsoft有一个叫做的部门Desktop SoftwareSoftware Development DBMS 只能假设它已经给出了一个真实的事实。
您的问题源于您的模型中缺少实体类型这一事实。考虑以下 ERD:
请注意,我在和之间添加了一个交集实体类型。这种新的实体类型:提供隐含在您的模型中的信息,即特定部门具有一组给定的各种分类的工作。DEPARTMENTCLASSIFICATIONPOSITION
添加POSITION到您的模型作为显式实体有几个优点。
WORKER可能被分配到不同公司的部门和分类的问题。WORKER该位置当前没有s,这很可能是有用的信息。请注意,为了避免为不同公司的部门和分类定义职位的问题,我扩展了DEPARTMENT和的键CLASSIFICATION,这很好,因为您可以在 Todd Everett 的回答中详细阅读。
注意
上面的模型假设了一个简化。具体来说,它假设每个位置只记录一次。这可能适合也可能不适合您的业务规则。如果您需要POSITION公司内同一部门和分类的多个记录,那么您可以在POSITION.