Istnieje technika zwana wersjonowaniem, która istnieje od wielu lat, ale jest w dużej mierze niewykonalna z kilku powodów. Istnieje jednak podobna technika, którą nazywam Wersją Normalną Formą, która okazała się bardzo przydatna. Oto przykład użycia tabeli Pracownicy.
Najpierw tworzona jest tabela statyczna. To jest główna tabela encji i zawiera statyczne dane o encji. Dane statyczne to dane, które nie powinny ulec zmianie w trakcie życia jednostki, takie jak data urodzenia.
create table Employees(
ID int auto_generated primary key,
FirstName varchar( 32 ),
Hiredate date not null,
TermDate date, -- last date worked
Birthdate date,
... -- other static data
);
Ważne jest, aby zdać sobie sprawę, że dla każdego pracownika jest jeden wpis, tak jak w przypadku każdej takiej tabeli.
Następnie powiązana tabela wersji. Ustanawia to 1-metrową relację ze statyczną tabelą, ponieważ może istnieć kilka wersji dla pracownika.
create table Employee_versions(
ID int not null,
EffDate date not null,
char( 1 ) IsWorking not null default true,
LastName varchar( 32 ), -- because employees can change last name
PayRate currency not null,
WorkDept int references Depts( ID ),
..., -- other changable data
constraint PK_EmployeeV primary key( ID, EffDate )
);
W uwadze do tabeli wersji znajduje się data wejścia w życie, ale nie ma pasującego pola, które już nie obowiązuje. Dzieje się tak, ponieważ gdy wersja zacznie obowiązywać, pozostaje ona w mocy, dopóki nie zostanie zastąpiona przez kolejną wersję. Kombinacja ID i EffDate musi być unikalna, więc nie może być dwóch wersji dla tego samego pracownika, które są aktywne w tym samym czasie, ani nie może być przerwy między końcem jednej wersji a rozpoczęciem następnej.
Większość zapytań będzie chciała znać aktualną wersję danych pracowników. Jest to zapewnione przez połączenie statycznego wiersza dla pracownika z wersją, która teraz obowiązuje. Można to znaleźć za pomocą następującego zapytania:
select ...
from Employees e
join Employee_versions v1
on v1.ID = e.ID
and v1.EffDate =(
select Max( v2.EffDate )
from EmployeeVersions v2
where v2.ID = v1.ID
and v2.EffDate <= NOW()
)
where e.ID = :EmpID;
Zwraca to jedyną wersję, która rozpoczęła się w najnowszej przeszłości. Użycie nierówności <=w sprawdzaniu daty (v2.EffDate <= NOW()
) pozwala na wprowadzenie dat w przyszłości. Załóżmy, że wiesz, że nowy pracownik rozpocznie pracę pierwszego dnia następnego miesiąca lub podwyżka jest zaplanowana na 13 dnia następnego miesiąca, te dane można wstawić z wyprzedzeniem. Takie „wstępnie załadowane” wpisy będą ignorowane.
Nie pozwól, aby podzapytanie do Ciebie dotarło. Wszystkie pola wyszukiwania są indeksowane, więc wynik jest dość szybki.
Ten projekt zapewnia dużą elastyczność. Powyższe zapytanie zwraca najnowsze dane wszystkich pracowników, obecnych i przeszłych. Możesz sprawdzić TermDate
pole, aby zdobyć tylko obecnych pracowników. W rzeczywistości, ponieważ wiele miejsc w twoich aplikacjach będzie zainteresowanych tylko bieżącymi informacjami o obecnych pracownikach, to zapytanie będzie stanowić dobry widok (pomiń końcowe where
klauzula). Aplikacje nie muszą nawet wiedzieć o istnieniu takich wersji.
Jeśli masz konkretną datę i chcesz zobaczyć dane, które obowiązywały w tym czasie, zmień v2.EffDate <= NOW()
w podzapytaniu do v2.EffDate <= :DateOfInterest
.
Więcej szczegółów można znaleźć w prezentacji slajdów tutaj i nie do końca wypełnionym dokumencie tutaj.
Aby pokazać odrobinę rozszerzalności projektu, zauważ, że istnieje IsWorking
wskaźnik w tabeli wersji oraz data zakończenia w tabeli statycznej. Kiedy pracownik opuszcza firmę, ostatnia data jest wstawiana do tabeli statycznej i kopia najnowszej wersji z IsWorking
ustaw na false
zostanie wstawiony do tabeli wersji.
Często zdarza się, że pracownicy opuszczają firmę na jakiś czas, a następnie zostają ponownie zatrudnieni. Mając tylko datę w tabeli statycznej, wpis można aktywować ponownie, ustawiając tę datę z powrotem na NULL. Ale zapytanie „spojrzenie wstecz” za dowolny czas, gdy dana osoba nie była już pracownikiem, zwróciłoby wynik. Nic nie wskazywało na to, że opuścili firmę. Ale wersja z IsWorking
=false przy opuszczeniu firmy i IsWorking
=true, gdy powrót do firmy umożliwi sprawdzenie tej wartości w momencie zainteresowania i zignorowanie pracowników, którzy nie byli już pracownikami, nawet jeśli wrócili później.