【问题标题】:Recommended approach to merging two tables合并两个表的推荐方法
【发布时间】:2010-09-28 10:01:58
【问题描述】:

我有一个这样的数据库架构:

[Patients]                    [Referrals]
     |                             |
[PatientInsuranceCarriers]    [ReferralInsuranceCarriers]
                        \        /
                    [InsuranceCarriers]

PatientInsuranceCarriers 和 ReferralInsuranceCarriers 相同,只是它们引用的是患者或推荐人。我想合并这两个表,使其看起来像这样:

[Patients]      [Referrals]
       \           /
  [PatientInsuranceCarriers]
              |
      [InsuranceCarriers]

这里有两个选择

  • 要么创建两个新列 - ID_PatientOrReferral + IsPatient(将告诉我要引用哪个表)
  • 或创建两个不同的列 - ID_Patient 和 ID_Referral,两者都可为空。

一般来说,我会尽量避免使用可为空的列,因为我认为它们是一种不好的做法(意思是,如果你可以不使用空值,那么你就不需要可以为空的列)而且它们更难使用在代码中(例如,LINQ to SQL)。

但是我不确定第一个选项是否是个好主意。我看到可以在 ID_PatientOrReferral 上创建两个 FK(一个用于患者,一个用于推荐人),尽管由于明显的原因我无法在那里设置任何更新/删除行为,但我不知道插入的约束检查是否有效方式,要么,所以看起来 FK 只是为了标记存在关系。或者,我可能不创建任何外键,而是手动在 DBML 中添加关系。

是否有更好的方法?为什么?

【问题讨论】:

  • 为什么要合并它们?
  • 查询、报告和维护。除了 FK 之外,这两个表具有完全相同的列,我们现在有两个 LINQ to SQL 实体、单独的控制器和视图,并且在为报告准备数据时必须合并它们,因此建议将这两个表合并。

标签: sql-server linq-to-sql foreign-keys


【解决方案1】:

扩展我有点简洁的评论:

我想合并这两个表

我认为这是个坏主意。目前,您有两个具有清晰关系谓词的表(简而言之,表中存在记录意味着什么) - 至关重要的是,这些关系谓词是两个表不同

  • PatientInsuranceCarriers 中存在一条记录 PatientInsurance Carrier 相关联

  • ReferralInsuranceCarriers 中存在一条记录 ReferralInsurance Carrier 相关联

当然,它们很相似,但它们并不相同。现在考虑一下组合表的关系谓词是什么:

  • 一条记录存在于ReferralAndPatientInsuranceCarriers {(IsPatienttruePatient 的ID 为ID_PatientOrReferral) 或者(IsPatientfalseReferral 的ID ID_PatientOrReferral)} 与 Insurance Carrier 相关联

或者如果您使用NULLs 进行操作

  • ReferralAndPatientInsuranceCarriers 中存在记录 {(ID_Patient 不是 NULLPatient,ID 为 ID_Patient)或者(ID_Referral 不是 NULLReferral ID ID_Referral)} 与 Insurance Carrier 相关联

现在,我不是自动建议更复杂的关系词条必然更糟的人;但我很确定以上两者中的任何一个都比它们要取代的更糟糕。


解决您的疑虑:

我们现在有两个 LINQ to SQL 实体,每个实体都有单独的控制器和视图

总的来说,我同意减少重复;然而,只是重复同样的事情!在这里,以上这些本质上不是“样板”,它们的构建和维护都可以委托给合适的开发工具吗?

并且在为报告准备数据时必须合并它们

如果您要创建一个包含UNIONVIEW,用于报告目的,您将保持实际数据的简单性,并且仍然能够在组合列表上进行报告;例如(对列名等做出假设):

CREATE VIEW InterestingInsuranceCarriers
AS
SELECT 
    IC.Name InsuranceCarrierName
    , P.Name CounterpartyName
    , 'Patient' CounterpartyType
FROM InsuranceCarriers IC
    INNER JOIN PatientInsuranceCarriers PIC ON IC.ID = PIC.InsuranceCarrierID
    INNER JOIN Patient P ON PIC.PatientId = P.ID
UNION
SELECT 
    IC.Name InsuranceCarrierName
    , R.Name CounterpartyName
    , 'Referral' CounterpartyType
FROM InsuranceCarriers IC
    INNER JOIN ReferralInsuranceCarriers RIC ON IC.ID = RIC.InsuranceCarrierID
    INNER JOIN Referral R ON PIC.ReferralId = R.ID

【讨论】:

  • 这似乎不是最好的主意,我同意你的看法。我设法说服我的客户退出合并,而且,不久之后,我不得不创建一个可以合并这样的表的解决方案 - 我选择了 3 个表,而不是 1 个。我在查询这样的结构时没有任何问题,并且会尽量避免合并表,它对查询没有任何帮助......
【解决方案2】:

this question复制我的答案

如果你真的需要 TableZ 中的A_or_B_ID,你有两个类似的选择:

1) 将可空的A_IDB_ID 列添加到表z,使A_or_B_ID 成为对这两个列使用ISNULL 的计算列,并添加一个CHECK 约束,使得只有A_IDB_ID 之一不为空

2) 向表 z 添加一个 TableName 列,限制为包含 A 或 B。现在创建 A_IDB_ID 作为计算列,它们仅在其相应的表被命名时才为非空(使用 CASE 表达式)。让他们也坚持下去

在这两种情况下,您现在都有 A_IDB_ID 列,它们可以有适当的外部 基表的键。不同之处在于计算哪些列。还有,你 如果 2 个 ID 列的域不需要,则不需要上面选项 2 中的 TableName 重叠 - 只要您的案例表达式可以确定哪个域 A_or_B_ID 落入

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多