كيفية إعادة بناء البيانات بكفاءة - إصدارها من قبل الحقول الفردية ، فقط تلك التي تغيرت

StackOverflow https://stackoverflow.com/questions/19846759

سؤال

لديّ DB Legacy مع بعض الجداول التي يتم إصدارها بالطريقة التالية: كل حقل بشكل فردي - فقط تلك التي تغيرت ؛

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