문제

나는 일부 테이블이 다음과 같은 방식으로 버전을 갖는 레거시 DB를 가지고 있습니다. 각 필드는 개별적으로 - 그리고 변경된 것만;

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로 수행 할 수 있습니까? 감사!

도움이 되었습니까?

해결책

레코드를 재구성 할 수 있습니다. 쿼리는 약간 번거 롭습니다. 논리는 주어진 필드에 대해 다음을 수행하는 것입니다. 값은 다음 규칙에 따라 제공됩니다.

  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 join ~와 함께 seqnum = 1 이것을 처리합니다. 현재 값은 이전 또는 후속 값과 일치하지 않을 때만 사용됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top