Det finns en teknik som kallas versionshantering som har funnits i många år men som i stort sett inte fungerar av flera skäl. Det finns dock en liknande teknik som jag kallar Version Normal Form som jag har tyckt vara väldigt användbar. Här är ett exempel som använder en tabell för anställda.
Först skapas den statiska tabellen. Detta är huvudentitetstabellen och den innehåller statisk data om entiteten. Statisk data är data som inte förväntas förändras under enhetens liv, till exempel födelsedatum.
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
);
Det är viktigt att inse att det finns en post för varje anställd, precis som med alla sådana bord.
Sedan den tillhörande versionstabellen. Detta etablerar en 1-m relation med den statiska tabellen eftersom det kan finnas flera versioner för en anställd.
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 )
);
I versionstabellanteckningen finns ett ikraftträdandedatum men inte ett matchande fält som inte längre är i kraft. Detta beror på att när en version väl träder i kraft förblir den i kraft tills den ersätts av den efterföljande versionen. Kombinationen av ID och EffDate måste vara unik så att det inte kan finnas två versioner för samma anställd som är aktiva samtidigt, och det kan inte heller finnas ett gap mellan det att en version slutar och när nästa version startar.
De flesta frågor kommer att vilja veta den aktuella versionen av personaldata. Detta tillhandahålls genom att sammanfoga den statiska raden för medarbetaren med den version som gäller nu. Detta kan hittas med följande fråga:
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;
Detta returnerar den enda versionen som startade i det senaste. Använder olikheten <=i datumkontrollen (v2.EffDate <= NOW()
) möjliggör ikraftträdande datum i framtiden. Anta att du vet att en ny anställd kommer att börja den första dagen i nästa månad eller att en lönehöjning är planerad till den 13:e nästa månad, kan denna information infogas i förväg. Sådana "förladdade" poster kommer att ignoreras.
Låt inte underfrågan komma till dig. Alla sökfält är indexerade så resultatet är ganska snabbt.
Det finns mycket flexibilitet med denna design. Frågan ovan returnerar den senaste informationen för alla anställda, nuvarande och tidigare. Du kan kontrollera TermDate
fält för att få just närvarande medarbetare. Faktum är att en hel del platser i dina appar bara är intresserade av aktuell information om nuvarande anställda, skulle den frågan ge en bra bild (utelämna den sista where
klausul). Apparna behöver inte ens veta att sådana versioner finns.
Om du har ett visst datum och du vill se data som gällde vid den tidpunkten, ändra sedan v2.EffDate <= NOW()
i underfrågan till v2.EffDate <= :DateOfInterest
.
Mer information finns i en bildpresentation här och ett inte helt färdigt dokument här.
För att visa upp lite av designens töjbarhet, lägg märke till att det finns en IsWorking
indikator i versionstabellen samt ett uppsägningsdatum i den statiska tabellen. När en anställd lämnar företaget infogas sista datum i den statiska tabellen och en kopia av den senaste versionen med IsWorking
inställd på false
infogas i versionstabellen.
Det är ganska vanligt att anställda lämnar ett företag ett tag och sedan anställs igen. Med bara datumet i den statiska tabellen kan posten aktiveras igen bara genom att ställa tillbaka det datumet till NULL. Men en "blick tillbaka"-fråga för varje tidpunkt då personen inte längre var anställd skulle returnera ett resultat. Det skulle inte finnas något som tydde på att de hade lämnat företaget. Men en version med IsWorking
=falskt när du lämnar företaget och IsWorking
=sant när du återvänder till företaget kommer att tillåta en kontroll av det värdet vid intressetillfället och ignorera anställda när de inte längre var anställd även om de återvände senare.