📜 ⬆️ ⬇️

Versioning of data in MySQL

In 1C there is a very useful feature - periodic details, with the help of them you can store not only the value, but also the entire history of its changes. For example, if we store the value of the dollar exchange rate in relation to the ruble, then not only the current value is stored, but also the value of yesterday, the day before yesterday, etc. (the storage period can be any). In MySQL, unfortunately, there is no such feature (probably not necessary). So let's do it ourselves;).

Consider an example. Suppose we have a simple filing system based on the TTroubleticket table.
Table TTroubleticket
fkeyrequest number
fcontactapplication contact information
ftextapplication text

In addition to contact information and the text of the application, you must keep the status of the application with the entire history of its changes. Such a solution immediately suggests itself: store the status in another table with the entire history of changes.
TStatusHistory table
fkey
f_troubleticketlink to entry in TTroubleticket
fvaluevalue
fsdatedate of assignment

Then to get the current value we need to run the following query:
     SET @f_troubleticket = 10;
     SELECT
         tt.fkey, tt.fcontact, tt.ftext,
         (SELECT 
             fvalue 
          FROM 
             TStatusHistory 
          WHERE 
             f_troubleticket = tt.fkey 
          ORDER BY 
             fsdate DESC 
          LIMIT 0.1
         ) AS fstatus
     FROM 
         TTroubleticket AS tt
     WHERE
         fkey = @f_troubleticket
     LIMIT 0, 1 


Everything is smooth, everything is good, nothing superfluous, but if you wish, we can always view the entire history of status changes. The first difficulties will begin when we try to get the value on some date. Therefore, we will add another fedate field - the date when the value action ends. Let redundant information be stored in this field, but it will make life very useful for us.
TStatusHistory table
fkey
f_troubleticketlink to entry in TTroubleticket
fvaluevalue
fsdatedate of assignment
fedate datecompletion action values


Now, to get the value for the date, we need to change the query a little:
    
     SET @f_troubleticket = 10;
     SET @dt = 20090401000000;  # April 01, 2009 00:00
     SELECT
         tt.fkey, tt.fcontact, tt.ftext,
         (SELECT 
             fvalue 
          FROM 
             TStatusHistory 
          WHERE 
             f_troubleticket = tt.fkey 
             AND @dt BETWEEN fsdate AND fedate 
          ORDER BY 
             fsdate DESC 
          LIMIT 0.1
         ) as fstatus
     FROM 
         TTroubleticket AS tt
     WHERE
         fkey = @f_troubleticket
     LIMIT 0, 1

')
With this complexity handled. But time goes on, and the system is improving: we needed such a parameter as the type of application and also periodic. Bullshit! -Add more table.
TTypeHistory table
fkey
f_troubleticketlink to entry in TTroubleticket
fvaluevalue
fsdatedate of assignment
fedateexpiration date of the value


Zaros converted:
    
     SET @f_troubleticket = 10;
     SET @dt = 20090401000000;  # April 01, 2009 00:00
     SELECT
         tt.fkey, tt.fcontact, tt.ftext,
         (SELECT 
             fvalue 
           FROM 
             TStatusHistory 
           WHERE 
             f_troubleticket = tt.fkey 
             AND @dt BETWEEN fsdate AND fedate 
           ORDER BY 
             fsdate DESC 
           LIMIT 0.1
         ) AS fstatus,
         (SELECT 
             fvalue 
           FROM 
             TTypeHistory 
           WHERE 
             f_troubleticket = tt.fkey 
             AND @dt BETWEEN fsdate AND fedate 
           ORDER BY 
             fsdate DESC 
           LIMIT 0.1
         ) AS ftype
     FROM 
         TTroubleticket AS tt
     WHERE
         fkey = @f_troubleticket 
     LIMIT 0, 1 

And over time, we may receive a bunch of additional tables, i.e. the system is complicated, and there is nothing good about it.
We will improve our approach - we will not create separate tables for each periodic variable, we will store all periodic variables in one table.
Table thistory
fkey
f_troubleticketlink to entry in TTroubleticket
fstatusstatus
ftypetype of
fsdate datevalue assignments
fedate datecompletion action values


Also, all current values ​​will be stored in the main table.

Table TTroubleticket
fkeyrequest number
fcontactapplication contact information
ftextapplication text
fstatuscurrent status
ftypecurrent type


And now when we need to get the actual values, we just need to perform a simple query:
    
     SET @f_troubleticket = 10;
     SELECT
         fkey, fcontact, ftext,
         fstatus
         ftype
     FROM 
         TTroubleticket
     WHERE
         fkey = @f_troubleticket
     LIMIT 0, 1 



Well, if we need to get the values ​​for the date, we use the LEFT JOIN construction:
    
     SET @f_troubleticket = 10;
     SET @dt = 20090401000000;  # April 01, 2009 00:00
     SELECT
         tt.fkey, tt.fcontact, tt.ftext,
         his.fstatus
         his.ftype
     FROM 
         TTroubleticket AS tt
             LEFT JOIN TTroubleticketHistory as his 
                 ON his.f_troubleticket = tt.fkey 
                      AND @dt BETWEEN his.fsdate AND his.fedate
     WHERE
         tt.fkey = @f_troubleticket
     LIMIT 0, 1 



That's all. It seems to be a very difficult decision. And how do you store periodic values?

ps Thanks for the idea A. Matveyev.

Source: https://habr.com/ru/post/58293/


All Articles