SQL 2005/2008数据库跟踪字段更改

时间:2011-01-27 12:02:43

标签: sql-server database-design data-structures

想要审核或历史记录跟踪。

我有一个应用程序从外部源提取数据。 我们在自己的DB中镜像外部表。我们允许用户更新数据库中的数据。 下次系统与外部数据同步时,我们只会覆盖我们未在本地更改的字段。

在我的头脑中,我可以想到两种方法来做到这一点

1)为每个对象存储2行。第一个是外部版本,第二行链接到外部版本,但如果该字段已更改,则只在字段中包含数据。 e.g。

id      |     parentId    |    field1      | field2
1       |      null       |     foo        |   bar
2       |        1        |     new foo    |   null

这说明了本地用户更改field1时的数据。 如果没有发生变化,那么只会有第一行。

2)将表格中的列数加倍。 例如 name_external name_internal

我更喜欢选项1,因为它似乎可以提供更好的分离,更容易查询和在2个对象之间进行代码比较。唯一的缺点是它会产生更多的行,但DB会很小。

我可以使用其他任何模式吗?或者我不应该选择选项1的原因。

我将使用.NET 4 WCF服务


解决方案

我将使用下面提供的两个表格答案。并使用以下SQL返回一个Row,其中包含已在本地更改的字段与原始值

合并
SELECT 
    a.[ID], 
    isnull(b.[firstName], a.[firstName]),
    isnull(b.[lastName], a.[lastName]), 
    isnull(b.[dob], a.[dob]), 
    isnull(b.active, a.active)
From tbl1 a
left join tbl2 b on a.[ID] = b.[ID]

与我一样,DB只能通过UI系统进行更新。我可以确保不允许人们输入NULL作为值,而是强制他们输入空字符串。这将允许我克服在用户将值更新为NULL时发生的问题

2 个答案:

答案 0 :(得分:1)

如果您选择选项1,我可以考虑两个问题。

允许用户更新数据意味着您必须编写过程来为它们执行insert / update / delete语句,管理双行结构,或者您必须训练所有用户正确更新表。 / p>

另一个问题是建模表中的字段可能为NULL。如果使用NULL表示字段未更改,您如何表示字段更改为NULL?

将列数加倍的第二个选项可以避免更新的复杂性并允许您存储NULL值,但是由于行大小的增加以及服务器必须移动的数据量,您可能会看到性能下降(没有测试它我意识到这个说法没有事实根据,但我认为值得一提。)

另一个建议是复制表,也许将它们放在另一个模式中,该模式在执行与外部数据源的同步之后保存数据的快照。

我知道您不希望进行全面审核,这将是某个时间点的数据副本。然后,您可以允许用户根据需要修改数据,而不会产生双行/列的复杂性,当您与外部源重新同步时,您可以找出哪些字段已更改。

我发现了一篇很棒的文章:The shortest, fastest, and easiest way to compare two tables in SQL Server: UNION!描述了这样的比较。

答案 1 :(得分:0)

考虑使用更新触发器来更新UpdatedBy字段。我们有一个用于导入的用户,如果导入完成,则不允许其他进程使用该用户更新字段。因此,如果用户-1以外的任何值是最后一次更新,您可以轻松判断。然后,您可以使用合并语句来插入/删除/更新。