0

我有一个遗留数据库,其中一些表按以下方式进行版本控制:每个字段单独 - 并且只有那些发生变化的字段;

Table1

ObjID  userID  Data1    Data2  Data3
-----  ------  -----    ----   ---- 
11       1       A      null   123  
222      1       H      111    999
33       2       C      222    333


Table1_ver

ObjID   userID   FieldName    OldValue    VersionNumber
-----  ------     -----        ----        ----
222       1       Data1         F           5
222       1       Data1         A           8
222       1       Data2        888          10
33        8       Data1         G           10

当前版本存储在其他表中 - 假设现在是 11;当更改发生时,旧数据值与“旧”版本号(旧值所属的那个)一起记录,然后版本号增加

这些表有很多字段(> 20)和很多记录,所以我猜最初的想法是使用更少的存储来进行版本控制。现在我需要添加功能以在给定的时间点(按版本)重建数据。我怎样才能以一种优雅而有效的方式做到这一点——最好不使用动态 SQL,而是使用一些基于集合的方法。是否可以在 SQL 中以良好的性能完成?谢谢!

4

1 回答 1

3

您可以重建记录。查询会有点麻烦。逻辑是对给定字段执行以下操作,其值由以下规则给出:

  1. 下一个版本小于@VersionNumber 的记录的新值
  2. 具有比@VersionNumber 更高版本的记录的旧值
  3. 当前值

这是一个示例(字段较少):

select t1.objId, t1.userId,
       max(case when tv.FieldName = 'Data1' and VersionNumber < @VersionNumber
                then tv.NewValue
                when tv.FieldName = 'Data1' and VersionNumber > @VersionNumber
                then tv.OldValue
                when tv.FieldName = 'Data1' and VersionNumber is null
                then t.Data1
           end) as Data1,
       max(case when tv.FieldName = 'Data2' and VersionNumber < @VersionNumber
                then tv.NewValue
                when tv.FieldName = 'Data2' and VersionNumber > @VersionNumber
                then tv.OldValue
                when tv.FieldName = 'Data2' and VersionNumber is null
                then t.Data2
           end) as Data2,
      . . . 
from table1 t1 left outer join
     (select tv.*,
             row_number() over (partition by objId, userId, fieldname
                                order by abs(VersionNumber - @VersionNumber)
                               ) as seqnum
      from table_var tv
     ) tv
     on tv.objId = t.objId and tv.userId = t.userId and seqnum = 1
group by t1.objId, t1.userId;

这种逻辑的一个挑战是确保当前值不会意外地混入先前的值。left outer joinwithseqnum = 1处理这个。当前值仅在与前一个或后一个值不匹配时使用。

于 2013-11-07T21:52:03.697 回答