合并数据的数据库架构设计模式

Rob*_*est 9 merge database-design design-patterns database-schema

我们有一个相当陈旧的数据库,其中包含大量个人以及他们已完成的一些成就.历史上几乎没有什么可以阻止重复的个人数据,因此我们最终遇到了数据非常脏的情况.可以在此处找到大量简化的版本.

我们现在正在重新设计架构和用户界面.我们将为用户提供将他们的个人合并在一起的工具.在提供的例子中,戴夫和大卫显然是同一个人,总共取得了4项成就.

鉴于用户犯错并且涉及的表比示例中多得多,我正在寻找一种便于数据合并的架构设计,特别是如果(当!)用户不可避免地合并数据犯了一个错误.

某种链接列表似乎是一种解决方案,但对于此用例并不完全有效.还有其他概念可能会适应这种情况吗?任何可能适合的特定设计模式?

编辑:由于SQLFiddle今天相当不稳定,这里是sqlfiddle上的create/insert/select sql:

CREATE TABLE individual
    (`individual_id` int, `forename` varchar(50), `surname` varchar(50))
;

CREATE TABLE achievement
    (`achievement_id` int, `name` varchar(50), `description` varchar(50))
;

CREATE TABLE individual_achievement
    (`individual_id` int,`achievement_id` int)
;

INSERT INTO individual
    (`individual_id`, `forename`, `surname`)
VALUES
    (1, 'Dave', 'Deane'),
    (2, 'David', 'Deane')
;

INSERT INTO achievement
    (`achievement_id`, `name`, `description`)
VALUES
    (1, 'unit_1', 'Unit 1'),
    (2, 'unit_2', 'Unit 2'),
    (3, 'unit_3', 'Unit 3'),
    (4, 'unit_4', 'Unit 4')
;

INSERT INTO individual_achievement
    (`individual_id`,`achievement_id`)
VALUES
    (1, 1),
    (1, 3),
    (2, 2),
    (2, 4)
;

select * from individual i
join individual_achievement ai using (individual_id)
join achievement a using (achievement_id)
Run Code Online (Sandbox Code Playgroud)

编辑2:刚刚发现这个非常相似的问题,希望在4年内也可能有其他解决方案.

Phi*_*ley 4

这里\xe2\x80\x99是你可以使用的一种策略。

\n\n

首先,创建一个新表,暂时将其命名为\xe2\x80\x9cIndividual_v2\xe2\x80\x9d,其列与原始表Individual 完全相同。(理想情况下,您最终将用此表替换 individual;实际上,人们可能仍然将数据输入到 individual 中,并且您\xe2\x80\x99 必须通过移动或合并来 \xe2\x80\x9cclean\xe2\x80\x9d 数据将其添加到Individual_v2 中。)使用成就链接配置此表。(目前,I\xe2\x80\x99m 假设成就是干净的。)

\n\n

然后,创建一个 \xe2\x80\x9cMapping\xe2\x80\x9d 表,如下所示:

\n\n
IndividualMapping\n\nOldIndividual_Id\nNewIndividual_Id\nCreatedAt\nCreatedBy\nApprovedAt  --  Nullable!\nApprovedBy  --  Nullable!\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x9cCreated\xe2\x80\x9d 列用于确定映射的创建时间和创建者(或对象)。

\n\n

\xe2\x80\x9cApproved\xe2\x80\x9d 列用于确定数据是否已迁移到新表。

\n\n

对于每个 \xe2\x80\x9cold\xe2\x80\x9d 项,您可以确定它在 \xe2\x80\x9cnew\xe2\x80\x9d 表中的映射位置;如果它不映射到任何现有项目,请在新表中为其创建一个。

\n\n

然后,在映射表中添加一个条目。如果创建了新项目,请将其标记为已批准;如果置信度高,则将其标记为已批准;否则,将其保留 \xe2\x80\x9cunapproved\xe2\x80\x9d 并等待审核。在适当的时候,审阅者将仔细检查并批准映射,将映射更改为不同的现有新项目,或者创建另一个新项目并映射到它。

\n\n

完成后,\xe2\x80\x9creal\xe2\x80\x9d 工作将针对新表完成。旧表和映射表可用于识别新数据的来源,并在必要时撤消/更改映射。

\n\n

这里有很多未解决的实施和支持问题,总的来说,这看起来很尴尬。从长远来看,一旦您解决了重复数据的问题,您就可以删除旧的(和映射)表,但在那之前您将拥有一个挑剔的系统。

\n\n
\n\n

附加物

\n\n

我\xe2\x80\x99m在这里谈论事情,没有进行详尽的分析。我认为你\xe2\x80\x99所描述的系统将会很繁琐,并且概念上很复杂,即使表格相对简单,并且最终细节超出了SO问题的范围。同样,很大程度上取决于系统及其重新设计的总体目标和目的。I\xe2\x80\x99m 将在这里做出一些假设:

\n\n
    \n
  • \xe2\x80\x9ceexisting\xe2\x80\x9d 系统将保留在原处

  • \n
  • 如此报名的个人(及其奖项)必须像往常一样立即提供。

  • \n
  • 将继续输入重复项;如果、何时并且在可行的情况下,它们将与预先存在的条目一起\xe2\x80\x9cconsolidated\xe2\x80\x9d

  • \n
\n\n

通过这种方式,系统将按如下方式工作:

\n\n
    \n
  • 在Individuals_v2 和Achievement 之间存在\xe2\x80\x99s 一个单独的关系表(目前为Individual_Achievement_v2,尽管必须有一个更好的名称)。

  • \n
  • \xe2\x80\x9cv2\xe2\x80\x9d 表中的数据是正确的、良好的、正确的。\xe2\x80\x9cv1\xe2\x80\x9d 表是暂存、历史、日志数据。

  • \n
  • 准备初始版本,其中v1 表中的所有条目都在 v2 表中配置。如果可以在此步骤中合并行,那就更好了。所有内容都会记录在 \xe2\x80\x9cmap\xe2\x80\x9d 表中,以便在必要时可以干净地返回并重做。

  • \n
  • 从此版本开始,新数据将输入到 v1 表中,并同时/立即输入到 v2 表中。如果可以映射到现有项目,请执行此操作,否则在 v2 表中创建新条目。始终在 \xe2\x80\x9cmap\xe2\x80\x9d 表中记录活动。

  • \n
  • 展望未来,所有 \xe2\x80\x9cLive\xe2\x80\x9d 查询都会命中 v2 表。v1 表(再次)是历史记录、日志、审计跟踪。一旦填充,它们就永远不会被修改,而 v2 表(包括映射表)可以并且将会被修改。

  • \n
  • 根据业务的确定,对数据进行定期审查/检查,以查找并修复随时间推移出现的重复条目,以及 \xe2\x80\x9cinvalid 重复项\xe2\x80\x9d(不正确的映射)。这是您执行回滚/重做工作的时间,如映射和 v1 表中所跟踪的那样。

  • \n
\n\n

你\xe2\x80\x99可能需要一些额外的日志表,来跟踪\xe2\x80\x9之类的东西,通过xx/xx/xxxx输入的数据是有效的,从那时起输入的数据必须经过检查\xe2\x80\x9d。我\xe2\x80\x99m确信还会出现其他问题和微妙之处\xe2\x80\x94他们总是这样做\xe2\x80\xa6

\n