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年内也可能有其他解决方案.
这里\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\nIndividualMapping\n\nOldIndividual_Id\nNewIndividual_Id\nCreatedAt\nCreatedBy\nApprovedAt -- Nullable!\nApprovedBy -- Nullable!\nRun 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我\xe2\x80\x99m在这里谈论事情,没有进行详尽的分析。我认为你\xe2\x80\x99所描述的系统将会很繁琐,并且概念上很复杂,即使表格相对简单,并且最终细节超出了SO问题的范围。同样,很大程度上取决于系统及其重新设计的总体目标和目的。I\xe2\x80\x99m 将在这里做出一些假设:
\n\n\xe2\x80\x9ceexisting\xe2\x80\x9d 系统将保留在原处
如此报名的个人(及其奖项)必须像往常一样立即提供。
将继续输入重复项;如果、何时并且在可行的情况下,它们将与预先存在的条目一起\xe2\x80\x9cconsolidated\xe2\x80\x9d
通过这种方式,系统将按如下方式工作:
\n\n在Individuals_v2 和Achievement 之间存在\xe2\x80\x99s 一个单独的关系表(目前为Individual_Achievement_v2,尽管必须有一个更好的名称)。
\xe2\x80\x9cv2\xe2\x80\x9d 表中的数据是正确的、良好的、正确的。\xe2\x80\x9cv1\xe2\x80\x9d 表是暂存、历史、日志数据。
准备初始版本,其中v1 表中的所有条目都在 v2 表中配置。如果可以在此步骤中合并行,那就更好了。所有内容都会记录在 \xe2\x80\x9cmap\xe2\x80\x9d 表中,以便在必要时可以干净地返回并重做。
从此版本开始,新数据将输入到 v1 表中,并同时/立即输入到 v2 表中。如果可以映射到现有项目,请执行此操作,否则在 v2 表中创建新条目。始终在 \xe2\x80\x9cmap\xe2\x80\x9d 表中记录活动。
展望未来,所有 \xe2\x80\x9cLive\xe2\x80\x9d 查询都会命中 v2 表。v1 表(再次)是历史记录、日志、审计跟踪。一旦填充,它们就永远不会被修改,而 v2 表(包括映射表)可以并且将会被修改。
根据业务的确定,对数据进行定期审查/检查,以查找并修复随时间推移出现的重复条目,以及 \xe2\x80\x9cinvalid 重复项\xe2\x80\x9d(不正确的映射)。这是您执行回滚/重做工作的时间,如映射和 v1 表中所跟踪的那样。
你\xe2\x80\x99可能需要一些额外的日志表,来跟踪\xe2\x80\x9之类的东西,通过xx/xx/xxxx输入的数据是有效的,从那时起输入的数据必须经过检查\xe2\x80\x9d。我\xe2\x80\x99m确信还会出现其他问题和微妙之处\xe2\x80\x94他们总是这样做\xe2\x80\xa6
\n