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的位置进行筛选再次感谢,最后我根据您的建议使它工作了-我不得不在这里和那里更改它以适应我案例的特殊性,但仍然-它现在工作了!