Você pode reconstruir os registros. A consulta será um pouco pesada. A lógica é fazer o seguinte para um determinado campo, o valor é dado pelas seguintes regras:
- O novo valor do registro com a próxima versão menor que @versionNumber
- O valor antigo do registro com a próxima versão superior do que @versionNumber
- O valor atual
Aqui está um exemplo (com menos campos):
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;
Um desafio com essa lógica é ter certeza de que o valor atual não se mistura acidentalmente nos valores anteriores. o left outer join
com seqnum = 1
lida com isso. O valor atual é usado apenas quando não há correspondência com um valor anterior ou seguinte.