Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何高效地重建数据-由单个字段进行版本控制,仅更改那些字段_Sql_Sql Server 2008_Database Design_Versioning_Common Table Expression - Fatal编程技术网

Sql 如何高效地重建数据-由单个字段进行版本控制,仅更改那些字段

Sql 如何高效地重建数据-由单个字段进行版本控制,仅更改那些字段,sql,sql-server-2008,database-design,versioning,common-table-expression,Sql,Sql Server 2008,Database Design,Versioning,Common Table Expression,我有一个遗留数据库,其中一些表的版本控制方式如下:每个字段都是单独的,只有那些更改过的字段 Table1 ObjID userID Data1 Data2 Data3 ----- ------ ----- ---- ---- 11 1 A null 123 222 1 H 111 999 33 2 C 222 333 Table1_ver O

我有一个遗留数据库,其中一些表的版本控制方式如下:每个字段都是单独的,只有那些更改过的字段

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中以良好的性能完成吗?谢谢

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

下一个版本小于@VersionNumber的记录的新值 下一个版本高于@VersionNumber的记录的旧值 当前值 下面是一个字段较少的示例:

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;

这种逻辑的一个挑战是确保当前值不会意外地与以前的值混合。seqnum=1的左侧外部联接处理此问题。当前值仅在与前面或后面的值不匹配时使用。

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

下一个版本小于@VersionNumber的记录的新值 下一个版本高于@VersionNumber的记录的旧值 当前值 下面是一个字段较少的示例:

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;

这种逻辑的一个挑战是确保当前值不会意外地与以前的值混合。seqnum=1的左侧外部联接处理此问题。当前值仅在与前面或后面的值不匹配时使用。

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

下一个版本小于@VersionNumber的记录的新值 下一个版本高于@VersionNumber的记录的旧值 当前值 下面是一个字段较少的示例:

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;

这种逻辑的一个挑战是确保当前值不会意外地与以前的值混合。seqnum=1的左侧外部联接处理此问题。当前值仅在与前面或后面的值不匹配时使用。

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

下一个版本小于@VersionNumber的记录的新值 下一个版本高于@VersionNumber的记录的旧值 当前值 下面是一个字段较少的示例:

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;

这种逻辑的一个挑战是确保当前值不会意外地与以前的值混合。seqnum=1的左侧外部联接处理此问题。当前值仅在与前面或后面的值不匹配时使用。

哇,这看起来太棒了!剩下的唯一问题是,我没有NewValue字段。我试图修改tv表表达式,比如-select tv.*,tv_new.OldValue为NewValue,按tv.objId、tv.userId划分的行数,tv.fieldname按Absv.VersionNumber排序-@VersionNumber作为seqnum从表1\u ver tv LEFT加入表1\u ver tv\u new on tv.objId=tv\u new.objId,其中tv.VersionNumber tv.VersionNumber和tv.fieldname=tv\u new.fieldname尚未完全工作,我想我也需要在这里重复seqnum技巧。还有一些发现-我们无法按tv.versionNumber的位置进行筛选再次感谢,最后我根据您的建议使它工作了-我不得不在这里和那里更改它以适应我案例的特殊性,但仍然-它现在工作了!哇,这看起来棒极了!剩下的唯一问题是,我没有NewValue字段。我试图修改tv表表达式,比如-select tv.*,tv_new.OldValue为NewValue,按tv.objId、tv.userId划分的行数,tv.fieldname按Absv.VersionNumber排序-@VersionNumber作为seqnum从表1\u ver tv LEFT加入表1\u ver tv\u new on tv.objId=tv\u new.objId,其中tv.VersionNumber tv.VersionNumber和tv.fieldname=tv\u new.fieldname尚未完全工作,我想我也需要在这里重复seqnum技巧。还有一些发现-我们不能按tv.versionNumber的位置进行筛选再次感谢,最后我根据你的建议使它工作了-我不得不在这里和那里更改它以适应我案例的特殊性,但仍然-它是工作的
国王现在!哇,这看起来棒极了!剩下的唯一问题是,我没有NewValue字段。我试图修改tv表表达式,比如-select tv.*,tv_new.OldValue为NewValue,按tv.objId、tv.userId划分的行数,tv.fieldname按Absv.VersionNumber排序-@VersionNumber作为seqnum从表1\u ver tv LEFT加入表1\u ver tv\u new on tv.objId=tv\u new.objId,其中tv.VersionNumber tv.VersionNumber和tv.fieldname=tv\u new.fieldname尚未完全工作,我想我也需要在这里重复seqnum技巧。还有一些发现-我们无法按tv.versionNumber的位置进行筛选再次感谢,最后我根据您的建议使它工作了-我不得不在这里和那里更改它以适应我案例的特殊性,但仍然-它现在工作了!哇,这看起来棒极了!剩下的唯一问题是,我没有NewValue字段。我试图修改tv表表达式,比如-select tv.*,tv_new.OldValue为NewValue,按tv.objId、tv.userId划分的行数,tv.fieldname按Absv.VersionNumber排序-@VersionNumber作为seqnum从表1\u ver tv LEFT加入表1\u ver tv\u new on tv.objId=tv\u new.objId,其中tv.VersionNumber tv.VersionNumber和tv.fieldname=tv\u new.fieldname尚未完全工作,我想我也需要在这里重复seqnum技巧。还有一些发现-我们无法按tv.versionNumber的位置进行筛选再次感谢,最后我根据您的建议使它工作了-我不得不在这里和那里更改它以适应我案例的特殊性,但仍然-它现在工作了!