Реестр/регистр предназначен для записи однотипных значений относящихся к различным контекстам в хронологическом порядке с целью иметь возможность получать для произвольного контекста последнее актуальное значение на произвольную точку шкалы времени.
Регистры чрезвычайно важны для создания современных информационных систем для хранения и представления данных в первичном ключе которых используется время.
Таблица регистра
Практически регистр является таблицей записей с составным ключом, который определяет контекст и содержит поле даты записи в составе ключа.
Для примера поля k1 и k2 определяют контекст, поле kts содержит время регистрации, v1 и v2 содержат полезные данные для хранения и выборки:
1 2 3 4 5 6 7 8 |
CREATE TABLE reg ( k1 varchar(4) NOT NULL, k2 int(4) NOT NULL, kts timestamp(0) NOT NULL, v1 varchar(4), v2 int(4), PRIMARY KEY (k1, k2, kts) ); |
Очевидный алгоритм
Выборка значений актуальных на определенную дату называют временным срезом. Для получения среза очевидным и несложным является выборка в два этапа:
- из записей заданного контекста выбрать наибольшее значение даты, что позволяет получить ключи для выборки последних записей
- выбрать записи по ключам последних записей
Запрос
1 2 3 4 5 6 7 8 9 |
SET @slice := '2023-10-07'; SELECT reg.k1, reg.k2, reg.kts, v1, v2 FROM reg INNER JOIN ( SELECT k1, k2, MAX(kts) AS last FROM reg WHERE kts<=@slice GROUP BY k1, k2) AS lasts ON reg.k1=lasts.k1 AND reg.k2=lasts.k2 AND reg.kts=lasts.last ORDER BY k1, k2, kts |
Альтернативный алгоритм
Выборка значений актуальных на определенную дату часто называют временным срезом. Для получения среза необходимо выполнить алгоритм:
- выбрать записи контекста заданного k1 и k2
- упорядочить группы каждого контекста по времени kts
- маркировать последнюю запись в каждой группе
- выбрать маркированные записи
Нюанс реализации состоит в том, что п.3 маркирования последней записи легко решается алгоритмическими средствами, и громоздко решается средствами SQL.
Запрос
//
1 2 3 4 5 6 7 8 9 |
SET @slice := '2023-10-07'; SELECT k1, k2, kts, v1, v2 FROM ( SELECT *, IF(k1=@k1 AND k2=@k2, 0, 1) AS terminal, @k1:=k1, @k2:=k2 FROM reg, (SELECT @k1:=0, @k2:=0) AS vars WHERE kts<=@slice ORDER BY k1,k2,kts DESC) AS subset WHERE terminal=1 |
Поскольку в SQL 5.x нет средств выделения групп в выборке, в запросе применен искусственный прием. В первом каскаде выборки создаются переменные @k1 и @k2, которые на этом этапе получают пустые значения.
Во втором каскаде значения в переменных позволяют обнаружить начало новой группы по изменению ключевых полей, т.к. в первом каскаде поле даты kts сортируется по убыванию, то первая запись в группе является последней в хронологическом порядке. Эта запись в группе маркируется в поле trailer.
В третьем каскаде выбираются записи маркированные в поле trailer - это и есть записи среза.