繁体   English   中英

我该如何处理这个泛化设计问题?

[英]How can I handle this generalization design issue?

在我们的数据库 model 中,我们有一个受益人实体。 受益人可以是自然人公司受益人; 物理受益人具有许多属性,例如姓名、姓氏、性别等; 此外,受益人(法人或自然人)可以是外国人,也可以不是; 这种进一步的区别转化为一组“通用”属性的不同域值(例如,在我居住的意大利,税号可能与英国的税号具有不同的数据格式)。

我们现在正在重新设计我们的受益人表,因为最初从事数据库分析和建模的开发人员做了一个(IMO)短视的选择。 他将主键约束放在属性 BeneficiaryName 上,该属性已用于存储公司名称(例如“Microsoft Corporation”)以用于公司受益人或姓氏(例如 Smith)用于实际受益人。 这样,我们就有了(不可接受的)约束,即我们的数据库中不能有超过 1 个姓“Smith”(或名为“Smith”的公司)的受益人。

我对这种“重构”的方法将引入对受益人实体的概括; 我会

  1. 清理受益人表,只保留常用数据;
  2. 在 Beneficiary 表中添加一个代理主键,我们称之为 BeneficiaryID;
  3. 拆分受益人表,创建两个子实体( CorporateBeneficiaryPhysicalBeneficiary ,由主受益人表中的标志区分),与受益人表有 1..1 关联(外键将引用 BeneficiaryID)
  4. 查找CorporateBeneficiaryPhysicalBeneficiary的(重要)主键;

这应该解决前面提到的 BeneficiaryName 唯一性问题。 到目前为止似乎还可以?

我遇到的真正问题是:我如何/应该如何处理这个 model 中“外来”属性添加的进一步复杂性? 我是否应该按原样保留外国,即受益人中的标志属性? 如果是这样,我如何在不重复属性(zipcode_foreign、zipcode、taxid_foreign、taxid 等)的情况下处理概念上相似的信息(即邮政编码、税号)对不同属性的需求? 我真的应该努力将不同的域值容纳到一个字段中吗?

任何建议都会受到欢迎...

“清理受益人表,只保留常用数据;”

正是有什么事情要做。

“在 Beneficiary 表中添加一个代理主键,我们称之为 BeneficiaryID;”

可能有用,但不要忘记如果存在“自然”标识符,那么它的唯一性也应该被强制执行。

“拆分受益人表,创建两个子实体(CorporateBeneficiary & PhysicalBeneficiary”

是的。 观察到很难强制执行“绝对”数据完整性(同时强制所有自然受益人都是受益人,所有非自然受益人也是受益人,并且所有受益人要么是自然受益人要么是非自然受益人)。

“被主受益人表中的标志区分”

没有。 不会那样做。 该标志是冗余的,冗余增加了复杂性而不增加价值。 如果您想知道受益人是自然人还是非自然人,请查看记录该事实的表格。

“为 CorporateBeneficiary 和 PhysicalBeneficiary 查找(重要的)主键;”

如果您一般为 Benficiaries 引入代理项,则无需在这些其他表中复制自然标识符。 这又是一种冗余,增加了复杂性而不增加价值。

“我遇到的真正问题是:我如何/应该如何处理这个 model 中的“外来”属性添加的进一步复杂性?”

可以应用相同的方法,区分 National 和 ExtraNational(对于公司和实体受益人),如果数据完整性在涉及到(例如,至少是 National Benficiaries)时至关重要,那么这可能是从建议到绝对需要的任何方法。 例如,法律可能会强制您根据国家规则验证国家 SSN 号码或国家公司识别号码是否“有效”。 如果此类法规适用,那么这些规则由 DBMS 签入和由DBMS 签入可能至关重要,而不仅仅是您的应用程序。 当然,对于非国民来说,通常也不需要进行类似的检查,甚至一般来说也不可能。

如果您在数据库结构中考虑到 National 和 Non-National 之间的这种区别,您很可能还希望创建一个将两者(National 和 Non-National)“联合”在一起的视图,然后您将不得不将您的数据“转换”为“统一”“通用”格式,这可能只是 CHAR(即使您知道,例如,对于 National PhysicalBeneficiaries,内容将是他们的 SSN 号码,您知道该号码由一些固定号码组成位数)。

如果您不必在数据库结构中考虑国家和非国家之间的这种区别,那么您将被迫在将保存数据的单个表中使用相同的“统一”“通用”格式对于国内和国外。

在一个字段中容纳不同的域值将复制您现在在主要受益人表中遇到的问题类型 - 在将来的某个时候。 我会采用这种方法:

修改 CorporateBeneficiary/PhysicalBeneficiary 表中的建议键,如下所示:

  1. 按照您的建议添加代理主键(BeneficiaryID)
  2. 使用适当的数据库或站点机制将 BeneficiaryID 生成为唯一的生成值。
  3. 使 CorporateBeneficiary (CB) 和 PhysicalBenificiary (PB) 的主键相同 - 即 BeneficiaryID。
  4. 将 CB 和 PB 的主键设为引用 Beneficiary 表的外键。

那么对于国外的细节采取类似的做法:

  1. 为每个国家添加一个包含公共列的表,但引用适当的域。
  2. 以与 CB/PB 类似的方式设置新表 - 即作为与受益人表的关系。

然后基于左连接创建视图以创建“虚拟表” - Beneficiary/PB/Foreign 详细信息。 这些视图将成为获取信息的基础。

如果您有非常大的数据集(> 10^7 行),您可能会发现我对验证邮政编码问题的回答很有趣。 这是一个很长的回应; 不简单; 并且是巨大的矫枉过正,除非体积非常大。

编辑

如果您的数据量较低,@James Anderson 建议的多行(例如地址)行将非常合适。

你的想法是正确的。

我建议您有一个单独的“地址”表供所有受益人共享。 (您实际上是在描述对人和公司相同的邮件投递。),但是这里处理 i18n 问题的最简单方法是保持简单的 Line1、Line2、Line3。 第 4 行和国家代码。

我什至不会 go 有一个特定的邮政编码,因为这些邮政编码从简单的 4 位数字到英国 /[A-Z0-9]{2,4} [A-Z0-9]{2,4 }/ 甚至是爱尔兰共和国,没有任何邮政编码(官方推理“哦,我们不需要那样的东西,我们知道你住在哪里。”)。 此外,邮政编码的常规 position 因国家/地区而异(UK 在其末尾单独一行,CH 在城市名称之前等),一些域跟随城市,县,state 模式其他地方没有有州或县或不在邮件地址中使用它们。

为了概括,您可以通过三个概念为数据库设计它们:

(解释 1 个泛化,2 个子类型)


1. 一张桌子供所有人使用

在这里,您在一张表中拥有来自泛化和子类型的所有属性。

优点:

  • 不需要 JOIN,不需要 UNION(=因此它通常是最快的可能性)
  • 轻松快速地从整个人群中获取东西
  • 轻松快速地摆脱泛化属性
  • 轻松快速地从子类型属性中获取内容

缺点:

  • 具有具有新属性的新子类型时重新设计表
  • 未使用属性的许多NULL 值
  • 用于标记特定记录是什么子类型的附加属性
  • (它看起来像丑陋的设计,但通常它是如此令人难以置信的快得多......)

PK/FK:一个 PK,没有 FK

对于您的示例:“受益人”只有一张表。


2.两张桌子

只有子类型的表。 没有表格可以概括。

优点:

  • 非常容易和快速地访问一个特定子类型的全部数据
  • 易于为特定子类型添加新属性

缺点:

  • 很难从整个人口中得到东西(UNION = 慢)
  • 难以为泛化添加新属性(必须更改所有表)

PK/FK:每张桌子都有自己的 PK,没有 FK

对于您的示例:“CorporateBeneficiary”和“PhysicalBeneficiary”的两个表


3. 三张桌子

有一个自己的表用于概括和每个子类型。 (这是你选择的。)

优点:

  • 轻松访问泛化属性
  • 轻松访问子类型属性
  • 易于添加新属性

缺点:

  • 获取整个实体的所有属性很昂贵(JOIN = 慢)

PKs/FKs:理想情况下,所有桌子都使用一个 PK 序列。 (即 Oracle 序列) 在子类型表中,pk 列同时是泛化表的 fk 列。 这在 DBMS 中可能有点复杂,因为您没有 Oracle 序列之类的东西。 可能需要在子类型中具有单独的 pk 和 fk 列,并为每个表提供自己的 PK 序列。 (即因为序列 gen 是一个列属性)


您选择哪一种取决于您的要求。 1.) 和 3.) 您会经常看到 2.) 的情况非常罕见,而且许多开发人员不知道这种设计。

就个人而言,当我没有其他边界条件时,我选择 3,因为我发现这是最干净的解决方案。 但由于性能原因,我过去也选择了选项 1。 不记得我从大学开始就做过类似选项 2 的事情。 :p

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM