我将首先创建一个包含所有客户的客户维度,并且每行只有一个客户。客户维度本身可以成为 CRM 和其他用途的有用工具,这意味着您将拥有一个单一、可靠的客户列表,这使得您随后实施的任何设计都变得更加容易。
之后,这取决于客户与合同之间的关系。我能想到的主要场景是 a) 一份合同有 4 个客户“角色”,b) 一份合同有 1-4 个客户,都具有相同的角色,c) 一份合同有 1-n 个客户,都具有同样的角色。
情景 A 是每个合同有 4 个客户角色,例如,一个客户请求合同,第二个签署合同,第三个见证合同,第四个支付合同费用。在这种情况下,您的事实表将有每个合同一行和 4 个客户 ID 列,每个列都引用客户维度:
...
RequesterCustomerID int,
SignatoryCustomerID int,
WitnessCustomerID int,
BillableCustomerID int,
...
当然,如果一个客户既是请求者又是见证人,那么您将在两者中拥有相同的 ID,RequesterCustomerID
因为WitnessCustomerID
您的客户维度中只有一行供他使用。这是完全正常的。
场景 B 是所有客户都有相同的角色,例如每个合同有 1-4 个签署者。如果签署人的数量永远不会超过 4,并且如果您非常有信心这将“始终”正确,那么简单的解决方案也是在事实表中为每个合约设置一行,其中 4 列引用客户维度:
...
SignatoryCustomer1 int,
SignatoryCustomer2 int,
SignatoryCustomer3 int,
SignatoryCustomer4 int,
...
即使大多数合同只有 1 或 2 个签署者,在表中使用 2 个不太常用的列也没有太大的危害。
场景 C 是一份合同有 1-n 个客户,其中 n 是一个变化很大的数字,甚至可能非常大(集体诉讼?)。如果您在一份合同上有 50 个客户,那么向事实表添加 50 列将变得难以管理。在这种情况下,我将添加一个名为ContractCustomers
或任何将事实表与客户维度联系起来的桥接表。这不像其他解决方案那样“简洁”,但是纯星型模式无论如何都不能很好地处理这样的 n:m 关系。
也可能有更复杂的情况,您将场景 A 和 C 混合在一起:合同有 3 个请求者、5 个签署者、2 个见证人,并且账单在请求者之间以 3 种方式拆分。在这种情况下,您将别无选择,只能创建某种包含每个合同的特定客户组合的桥接表,因为仅用一个事实和一个维度表无法清晰地表示它。