规范化和历史数据

时间:2010-10-13 18:49:50

标签: database database-design relational-model

在我描述我的问题之前,我想要完成一些事情:

  1. 我是一位经验丰富(虽然不专家)的数据库设计师。我相信我对关系模型有很好的把握。
  2. 我对关系模型没有如此坚定的理解,我知道在每种情况下应该做些什么。我还在学习。
  3. 假设我们每月从银行获得一份Excel电子表格,但并不总是相同的银行。电子表格只有六列:银行名称,帐号,帐户余额,客户(帐户)名称,客户SSN和帐户持有人地址。每行都有不同的帐号,并且没有帐号列在多行中。我们希望将此电子表格导入数据库,并在将来的任何时候说:“2010年10月13日John Smith的地址是什么?”

    为简单起见,假设每个客户只有一个地址,并且每个客户都可以拥有零个或多个帐户。而且只是一秒钟,让我们假装我们只需要做一个Excel表单导入EVER,这是一个愚蠢的前提,但请耐心等待。如果是这种情况,以下设计就足够了:

    bank
    --------
    id
    name
    
    account
    --------
    id
    bank_id
    customer_id
    number
    balance
    
    customer
    --------
    id
    name
    ssn
    address
    city
    state_id
    zip
    
    state
    --------
    id
    name
    

    我的问题的其余部分是基于你同意该架构是“正确的”的前提,所以希望你对它很好。

    现在,如果我们只进行一次进口,那就没关系了,但我们每年会进行12次进口。以下是我考虑这个问题的方法:

    bank
    --------
    id
    name
    
    account
    --------
    id
    import_id
    bank_id
    customer_id
    number
    balance
    
    customer
    --------
    id
    name
    ssn
    address
    city
    state_id
    zip
    
    state
    --------
    id
    name
    
    import
    --------
    id
    date
    excel_file (blob)
    

    现在每个帐户都与导入相关联,我们可以肯定地说“帐户12345来自10月13日的导入572”。当你看一下customer表时,它可能会有点模棱两可。由于customer表中的行数少于account表中的行数(因为有些客户有多个帐户),我们在客户和导入之间没有像我们这样的一对一关系用于帐户和进口。我知道没有数据丢失,并且没有数据完整性的损失,但它仍然感觉某种牺牲某种方式。

    我的问题是(这可能过于开放):您认为这是存储数据的好方法吗?你会以不同的方式做到吗?

    编辑:您必须了解这些实体的重要思考方式。不要将account视为一个随时间存在的帐户。将account视为特定时间点帐户的快照。因此,余额为100美元的帐户12345与帐户12345的余额为$ 150的account不同。是的,这两个记录都绑定在现实世界中的同一个银行帐户,但我存储的是某个时间点帐户的快照。与客户类似(但不完全相同)的情况。

6 个答案:

答案 0 :(得分:1)

对不起,我无法调和“每个客户只有一个地址”和“我们想说'2010年10月13日John Smith的地址是什么'”的陈述。您是否建议在每次导入时,为导入中找到的每个人创建客户记录?如果是这样,如果账号不同,你怎么知道一个导入中的John Smith与另一个导入的John Smith相同?

如果您为同一客户重复使用相同的客户记录(这对我来说似乎是对的),您在哪里可以找到先前的地址信息?

[经过海报评论和修改后]

好的,你快到了。您需要将客户地址添加到Account表(实际上应该重命名为AccountImports或类似的东西)。那是因为每个导入可能有不同的地址。

如果从导入到导入的地址经常保持不变,则在AccountImports中存储地址有点不正常。如果是这样,您可以添加CustomerAddressHistory表。在每次导入期间,检查CustomerAddressHistory中SSN的最新地址,如果与导入不同,则将新地址添加到该表中的新记录。

答案 1 :(得分:1)

不知道你正在使用什么数据库,但是这里有: 我不会将导入存储为blob,因为它阻碍了您与现有数据的链接,因为您必须先处理blob作为您希望它的文件类型加入任何其他数据。使用您已有的id和date字段将数据直接导入导入表。在{1}上设置ID,然后在日期,银行和帐户上设置key,以防止同日期重复。<​​/ p>

如果你确定你一年只会有12次进口(几个月,我推测?),你可以通过创建两个计算字段来增加完整性,一个用于date_month(用于保持月份),一个用于date_year (保持年度),然后在银行ID,帐户,date_month和date_year上创建unique compound index。这可以防止意外重新导入同一个月的不同日期的数据,比如10月的进口是在星期一完成,然后有人在周二再次进行。它还会阻止“我再次点击按钮的oops”或“oops,我导入本月的数据作为上个月的情景”。要加快对计算字段的检查,请在date_month和date_year上添加唯一索引。

如果您希望您的客户表始终反映当前地址而不用大惊小怪,请将地址设置为按客户帐户(或SSN等)查找导入表的计算字段,然后选择unique compound index地址按日期TOP 1排序。如果您希望查询或包含地址字段更快,请在其上添加索引。

答案 2 :(得分:0)

  1. 由于每次导入都与特定银行绑定,我可能会考虑将bank_id放入导入表中,并将其从帐户表中删除。
  2. 如果您想要考虑历史地址数据,并且只从导入中获取该数据,则可以将地址字段添加到帐户表中,然后将其从客户表中删除。当然,如果您有多个导入的相同地址,这样做会导致重复。如果您非常关心这一点,您可以添加另一个表,可能是“地址”,可能使用customer_id和address_id的复合主键。然后,您的导入表会添加address_id字段,您的导入代码需要检查该地址是否已存在。

答案 3 :(得分:0)

总的来说,这个设计看起来不错。

import / import_id本身在存储日期之外是否有任何意义?如果没有,我认为没有理由不完全排除该表并在帐户表上放置import_date。

此外,如果您需要历史地址信息,那么您还需要在customer表上使用import_id(或import_date :))。

<强>更新

如评论中所述,添加import_id不会考虑历史地址数据。

您需要的是某种customer_history表,它可以存储任何可能更改的数据,并通过外键链接回客户表。

customer
------
id
first_name
last_name (assuming name wouldn't change--it certainly could)


customer_history
-----------------
id
customer_id
import_id (or date)
(address fields)

如果帐户的详细信息可能会随着时间的推移而发生变化,那么您还需要一个历史记录表。

答案 4 :(得分:0)

我会谨慎地认为客户只有一个地址。 (在我的现实生活中,这不是真的)。您需要通过在每次加载时更新客户来存储您获得的最新地址,或者您应该考虑将地址拆分为新表并将其链接到客户 - 可能包含开始日期和结束日期以向您显示认为地址有效。

我认为我也不会将import_id放在帐户上。如果这样做,您将获得每个客户到银行连接的大量行(x12)。我认为不是你想要的。相反,您可以设置一个帐户到导入链接表,以告知您此帐户已在一个或多个导入中列出。

答案 5 :(得分:0)

我会创建一个名为 CustomerAddress 的新表,并将地址信息从客户中移出到这个新表中

然后在帐户表和 CustomerAddress 表中添加2个新列 StartDate EndDate

通过这种方式,您可以保留一行客户加班费,并可以轻松跟踪每个客户帐户和地址加班。如果你试图保留多个客户副本,那就太麻烦了。