Temporal database

En **temporal database** er en database som lagrer data knyttet til ulike tidsinstanser. Den tilbyr tidsbaserte datatyper, og lagrer informasjon relatert til fortid, nåtid og fremtid. En temporal database kan være enten unitemporal, bitemporal eller tritemporal som betyr at den henholdsvis har en, to eller tre tidsakser.

Vanlige temporale aspekter er gyldigtid, transaksjonstid og/eller beslutningstid:

* **Gyldigtid**: Tidsperioden eller tidsintervallet da noe (et «faktum») var sant i den virkelige verden
* **Transaksjonstid**: Tidspunktet da dataene ble registrert i databasen
* **Beslutningstid**: Tidspunktet da avgjørelsen ble tatt om et faktum. Brukt for å holde på historikk over beslutninger om gyldige tidsperioder.

## Etymologi
Ordet temporal stammer fra latin *tempus* og har grunnbetydning 'tid'.

## Unitemporal
En unitemporal database har én tidsakse, som enten er gyldighetsområdet eller systemtidsområdet.

## Bitemporal

En bitemporal database har to tidsakser:

* Gyldigtid, og
* Transaksjonstid *eller* beslutningstid

## Tritemporal

En tritemporal database har tre tidsakser:

* Gyldigtid,
* Transaksjonstid, og
* Beslutningstid

Denne tilnærmingen introduserer ytterligere kompleksiteter.

Temporale databaser står i motsetning til gjeldende databaser (ikke til å forveksle med tilgjengelige databaser) som bare lagrer fakta som antas å være sanne på det nåværende tidspunktet.

## Egenskaper
Temporale databaser støtter administrasjon av og tilgang til temporale data ved å tilby en eller flere av følgende funksjoner:

* En datatype for tidsperiode, inkludert muligheten til å representere tidsperioder uten ende (uendelig eller for alltid)
* Evne til å definere attributter og bitemporale relasjoner for gyldig-tidsperioder og transaksjons-tidsperioder
* Systemvedlikeholdt transaksjonstid
* Temporale primærnøkler, inkludert ikke-overlappende periodebegrensninger
* Temporale begrensninger, inkludert ikke-overlappende unikhet og referanseintegritet
* Oppdatering og sletting av temporale oppføringer med automatisk oppdeling og koalisering (sammenslåing) av tidsperioder
* Temporale spørringer på nåværende tidspunkt, tidspunkter i fortiden eller fremtiden, eller over varigheter (tidsintervaller)
* Predikater for spørring om tidsperioder, ofte basert på Allens intervallrelasjoner

## Historie
Med utviklingen av SQL og tilhørende bruk i anvendte applikasjoner innså databasebrukere enkelte problemer oppsto da de la til datokolonner i nøkkelfeltet. For eksempel hvis en tabell har en primærnøkkel og noen attributter, kan det å legge til en dato i primærnøkkelen for å spore historiske endringer føre til at det opprettes flere rader enn tiltenkt. Slettinger må også håndteres annerledes når rader spores på denne måten. I 1992 var dette problemet anerkjent, men standard databaseteori var ennå ikke i stand til å løse dette problemet, og heller ikke den da nylig formaliserte SQL-92-standarden.

I 1992 foreslo Richard Snodgrass at temporale utvidelser av SQL burde utvikles av det temporale databasemiljøet. Som svar på dette forslaget ble det dannet en komité for å designe utvidelser til 1992-utgaven av SQL-standarden (ANSI X3.135.-1992 og ISO/IEC 9075:1992); disse utvidelsene, kjent som TSQL2, ble utviklet i løpet av 1993 av denne komiteen. På slutten av 1993 presenterte Snodgrass dette arbeidet for gruppen som var ansvarlig for den amerikanske nasjonale standarden for databasespråket SQL, *ANSI Technical Committee X3H2* (senere kjent som NCITS H2). Den foreløpige språkspesifikasjonen dukket opp i publikasjonen *ACM SIGMOD Record* i 1994 mars. Basert på svar på denne spesifikasjonen ble det gjort endringer i språket, og den endelige versjonen av TSQL2-språkspesifikasjonen ble publisert i 1994 september.

Det ble gjort et forsøk på å innlemme deler av TSQL2 i den nye SQL-standarden  (også kalt SQL3). Deler av TSQL2 ble inkludert i en ny delstandard av SQL3, ISO/IEC 9075-7, kalt "SQL/Temporal". TSQL2-tilnærmingen ble sterkt kritisert av Chris Date og Hugh Darwen. ISO-prosjektet som var ansvarlig for temporal støtte ble kansellert nær slutten av 2001.

Per desember 2011 var det en klausul i *ISO/IEC 9075 Database Language SQL:2011 Part 2: SQL/Foundation* om tabelldefinisjoner for å definere såkalte "*application-time period tables*" (gyldigtid-tabeller), "*system-versioned tables*" (transaksjonstid-tabeller) og "*system-versioned application-time period tables*" (bitemporale tabeller). En vesentlig forskjell mellom TSQL2-forslaget og det som ble vedtatt I SQL:2011 er at det ikke er noen skjulte kolonner i SQL:2011-tilnærmingen, og det har heller ikke en ny datatype for intervaller. I stedet kan to dato- eller tidsstempel-kolonner bindes sammen ved å deklarere `PERIOD FOR`. En annen forskjell er erstatning av kontroversielle (prefiks) uttrykksmodifikatorer fra TSQL2 med en mengde temporale predikater.

Andre funksjoner  standarden relatert til temporale databaser er automatisk oppdeling av tidsperioder, temporale primærnøkler, temporal referanseintegritet, temporale predikater med Allens intervallalgebra og tidsinndelte (*time-sliced*) og sekvenserte spørringer.

## Eksempel
For illustrasjon, anta følgende korte biografi om en fiktiv kvinne, Kari Nordmann:

: Kari blir født 1975-04-03, og neste dag registrerte Kari sin far stolt datterens fødsel og at hun bor i Isfjorden. Etter ungdomssskolen flytter hun til Saltnes den 1994-08-26, men husker først den 1994-12-27 å registrere adresseendringen til Saltnes hvor hun har bodd i 4 måneder. 2001-04-01 dør Kari, og rettsmedisineren rapporterer dødsdatoen på samme dag.

### Bruk av ikke-temporal database
For å lagre livet til Kari Nordmann i en nåværende (ikke-temporal) database kan vi bruke vi en tabell . (For å forenkle designet er {Navn} definert som primærnøkkel av {Person}.

Far til Kari rapporterte offisielt inn fødselen 1975-04-04. På denne datoen ble følgende rad lagt inn i databasen: `Person (Kari Nordmann, Isfjorden)`. Merk at selve datoen ikke er lagret i databasen.

Etter endt utdanning flytter Kari ut, men glemmer å registrere sin nye adresse. Kari sin oppføring i databasen endres ikke før 1994-12-27 da hun endelig husker å rapportere det inn. Databasen blir da oppdatert i adressefeltet. Person-tabellen inneholder nå `Person (Kari Nordmann, Isfjorden)`. Merk at informasjonen om at Kari bodde i Isfjorden har blitt overskrevet, så det er ikke lenger mulig å hente den gamle informasjonen ut fra databasen. En person som fikk tilgang til databasen 1994-12-28 ville dermed bare fått ut faktaopplysningen om at Kari bor i Saltnes. Mer teknisk: Hvis en databaseadministrator kjørte spørringen  på datoen 1994-12-26 ville resultatet av spørringen vært `Isfjorden`, men om den samme spørringen hadde blitt kjørt 2 dager senere vil resultatet vært `Saltnes`.

Frem til hennes død ville databasen oppgitt at hun bodde i Saltnes. På 2001-04-01 slettes hun fra databasen etter at rettsmedisineren rapporterte inn hennes død. Deretter vil kjøring av spørringen ovenfor ikke gi noe resultat i det hele tatt.

### Bruk av 1 tidsakse: Gyldigtid eller transaksjonstid

Gyldigtid er tiden som et faktum er sant i den virkelige verden. En gyldig tidsperiode kan være i fortiden, spenne over nåværende tid, eller skje i fremtiden.

I eksempelet med Kari Nordmann over modifiseres person-tabellen ved å legge til de to kolonnene {Gyldig fra} og {Gyldig til}. Disse feltene spesifiserer når en adresse er gyldig i den virkelige verden. 1975-04-04 registrerte faren til Kari at hun hadde blitt født. Det kommer da inn en ny rad i databasen som sier at Kari bor i Isfjorden fra 1975-04-03. Merk at selv om dataene ble satt inn på den fjerde april, så sier databasen at informasjonen er gyldig siden tredje april. Det er ennå ikke kjent hvis eller når Kari flytter til et annet sted, så {Gyldig til} feltet er satt til uendelig (∞). Oppføringen i databasen er:
 Person(Kari Nordmann, Isfjorden, 1975-04-03, ∞).
1994-12-27 rapporterer Kari sin nye adresse i Saltnes hvor hun har bodd siden 1994-08.26. En ny databaseoppføring lages for å registrere dette faktum:

 Person(Kari Nordmann, Saltnes, 1994-08-26, ∞).

Den opprinnelige oppføringen `Person (Kari Nordmann, Isfjorden, 1975-04-03, ∞)` slettes ikke, men {Gyldig til}-attributten oppdateres for å gjenspeile at det nå er kjent at Kari sluttet å bo i Isfjorden 1994-08-26. Databasen inneholder dermed nå to oppføringer for Kari Nordmann:

 Person(Kari Nordmann, Isfjorden, 1975-04-03, 1994-08-26).
 Person(Kari Nordmann, Saltnes, 1994-08-26, ∞).

Når Kari dør oppdateres hennes nåværende oppføring i databasen slik at Kari ikke bor i Saltnes lenger. Databasen ser da slik ut:

 Person(Kari Nordmann, Isfjorden, 1975-04-03, 1994-08-26).
 Person(Kari Nordmann, Saltnes, 1994-08-26, 2001-04-01).

### Bruk av 2 akser: Gyldigtid og transaksjonstid
Transaksjonstid registrerer tidsperioden der en databaseoppføring aksepteres som riktig. Dette muliggjør spørringer som viser tilstanden til databasen på et gitt tidspunkt. Transaksjonstids-perioder kan bare forekomme i fortiden eller frem til nåtid. I en transaksjonstidstabell blir rader aldri slettet. Bare nye rader kan settes inn, og eksisterende oppdateres ved å angi transaksjonens sluttidspunkt for å vise at de ikke lenger er gjeldende.

For å ta med transaksjonstid i eksemplet med Kari ovenfor legges to felt til i person-tabellen: {Transaksjon fra} og {Transaksjon til}. {Transaksjon fra} er tidspunktet en transaksjon ble gjort, og {Transaksjon til} er tidspunktet transaksjonen ble erstattet (som kan være uendelig hvis den ennå ikke er erstattet). Dette gjør tabellen til en bitemporal tabell.

Anta at personens adresse som er lagret i databasen er feil (altså at det har blitt skrevet inn feil adresse eller dato med uhell, eller at det har blitt løyet om adressen, eller lignende), og at dette skal rettes opp i. Når feilen er oppdagelset skal den databasen oppdateres for å korrigere informasjonen som er registrert.

For eksempel, Fra 1995-06-01 til 2000-09-03 flyttet Kari til en pendlerbolig i Bøverdalen. Men for å unngå å betale skatt rapporterte hun det aldri til myndighetene. Senere under en skatteundersøkelse blir det oppdaget 2001-02-02 at hun faktisk var i Bøverdalen i løpet av disse datoene. For å registrere dette faktum må den eksisterende oppføringen om Kari som bor i Saltnes deles i to separate rader, og en ny rad blir satt inn for å registrere hennes bolig i Bøverdalen. Databasen vil da vises som følger:
 Person(Kari Nordmann, Isfjorden, 1975-04-03, 1994-08-26).
 Person(Kari Nordmann, Saltnes, 1994-08-26, 1995-06-01).
 Person(Kari Nordmann, Bøverdalen, 1995-06-01, 2000-09-03).
 Person(Kari Nordmann, Saltnes, 2000-09-03, 2001-04-01).
Dette etterlater imidlertid ingen historikk over at databasen tidligere hevdet at hun bodde i Saltnes fra 1995-06-01 til 2000-09-03. Dette kan være viktig å vite av revisjonsgrunner, eller for å bruke som bevis i skatteundersøkelsen. Transaksjonstid gjør det mulig å fange denne endrede kunnskapen i databasen, siden rader aldri blir direkte endret eller slettet. I stedet registrerer hver rad når den ble lagt inn og når den ble erstattet (eller logisk slettet). Databaseinnholdet vil dermed se slik ut:
 Navn, By, Gyldig fra, Gyldig til, Lagt inn, Erstattet

 Person(Kari Nordmann, Isfjorden, 1975-04-03, ∞, 1975-04-04, 1994-12-27).
 Person(Kari Nordmann, Isfjorden, 1975-04-03, 1994-08-26, 1994-12-27, ∞).
 Person(Kari Nordmann, Saltnes, 1994-08-26, ∞, 1994-12-27, 2001-02-02).
 Person(Kari Nordmann, Saltnes, 1994-08-26, 1995-06-01, 2001-02-02, ∞).
 Person(Kari Nordmann, Bøverdalen, 1995-06-01, 2000-09-03, 2001-02-02, ∞).
 Person(Kari Nordmann, Saltnes, 2000-09-03, ∞, 2001-02-02, 2001-04-01).
 Person(Kari Nordmann, Saltnes, 2000-09-03, 2001-04-01, 2001-04-01, ∞).

Databasen registrerer dermed ikke bare hva som skjedde i den virkelige verden, men også hva som var offisielt registrert til forskjellige tider.

### Bruk av 3 akser: Gyldigtid, beslutningstid og transaksjonstid

Beslutningstid er et alternativ til transaksjonstids-perioden for registrering av tidspunktet da en databaseoppføring kan aksepteres som riktig. Dette muliggjør spørringer som viser de offisielt anerkjente fakta på et gitt tidspunkt, selv om disse dataene kom forsinket inn i databasen. Støtte for beslutningstid bevarer hele historikken og forhindrer tap av informasjon under oppdateringer.

Beslutningsperioder kan bare forekomme i fortiden eller frem til transaksjonstiden. Som i en transaksjonstidstabell blir rader aldri slettet. Bare nye rader kan settes inn, og eksisterende oppdateres ved å angi beslutningstidens sluttidspunkt for å vise at de ikke lenger er gjeldende.

For å ta med beslutningstid kan man legge to felt til i en databasetabell: {Beslutning fra} og {Beslutning til}. {Beslutning fra} er tidspunktet en beslutning ble tatt, og {Beslutning til} er tidspunktet det en beslutning ble erstattet (som kan være uendelig hvis den ennå ikke er erstattet). Når det kombineres med transaksjonstid gjør det tabellen til en tritemporal tabell.

Følgende er en liste over virkelige hendelser som skjedde mellom presidentvalgene i USA i 1964 og 1976:

I dette eksempelet antas det en konstant 7-dagers forsinkelse mellom beslutningstidspunktet og transaksjonstidspunktet da dataene sendes inn til databasen. Etter valget i 1976 ville isåfall databasen innholdt følgende informasjon:

Gitt den tabellen over ville svaret på spørsmålet «hvem var president og visepresident for gyldigtiden 1977-01-01» (som gitt 7-dagers forsinkelse kan gi data for 1976-12-25) vært:

* Nixon/Agnew ved bruk av beslutningstid og transaksjonstid 1972-11-14
* Nixon/(Ledig) ved bruk av beslutningstid og transaksjonstid 1973-10-17
* Nixon/Ford ved bruk av beslutningstid og transaksjonstid 1974-08-08
* Ford/(Ledig) ved bruk av beslutningstid 1974-08-08 og gjeldende transaksjonstid
* Ford/Rockefeller ved bruk av gjeldende beslutningstid og transaksjonstid

## Bitemporal modellering

En bitemporal modell inneholder både gyldig- og transaksjonstid. Dette gir både historisk og tilbakerullings-informasjon. Historisk informasjon (for eksempel: "Hvor bodde Kari i 1992?") er gitt av gyldigtiden. "Hvor trodde databasen at Kari bodde i 1992?") er gitt av transaksjonstiden. Svarene på disse eksempelspørsmålene er kanskje ikke de samme –  siden databasen kan ha blitt endret siden 1992, hvilket førte til at disse to spørringene ga forskjellige resultater.

Gyldigtiden og transaksjonstiden trenger ikke å være den samme for et enkelt faktum. Anta for eksempel en temporal database som lagrer data om 1700-tallet. Gyldigtiden for disse faktaene er et sted mellom 1700 og 1799, mens transaksjonstiden vil vise når faktaene ble satt inn i databasen (for eksempel 1998-01-21).

## Skjemaevolusjon

Et utfordrende problem er å støtte temporale spørringer i en transaksjonstidsdatabase hvis skjema er under utvikling. For å oppnå perfekt arkivkvalitet er det viktig at dataene lagres under den skjemaversjonen de først dukket opp under. Imidlertid vil selv den enkleste temporale spørringen som omskriver historikken til en attributtverdi nødvendigvis bli omskrevet manuelt for hver av skjemaversjonene, som potensielt er hundrevis i tilfellet for MediaWiki. Denne prosessen vil være spesielt krevende for brukerne. En foreslått løsning er å muliggjøre automatisk omskriving av spørringer, selv om dette per nå ikke er en del av SQL eller lignende standarder.

Tilnærminger for å minimere kompleksiteten til skjemaevolusjoner er å: 

* Bruke en semistrukturert database/NoSQL-database som reduserer kompleksiteten ved å modellere attributtdata, men gir ingen funksjoner for håndtering av flere tidsakser.
* Bruke en database som kan lagre både semistrukturerte data for attributter og strukturerte data for tidsakser (for eksempel SnowflakeDB, PostgreSQL)

## Implementeringer i notable produkter
Følgende implementeringer gir temporale funksjoner i et relasjonsdatabasehåndteringssystem (RDBMS).

* MariaDB versjon 10.3.4 la til støtte for  standarden som "systemversjonerte tabeller".
* Oracle Database sin funksjon Oracle Workspace Manager gjør det mulig for applikasjonsutviklere og databaseadministratorer å administrere gjeldende, foreslåtte og historiske versjoner av data i samme database.
* PostgreSQL versjon 9.2 la til innebygde intervall-datatyper som er i stand til å implementere alle funksjonene i den temporale utvidelsen pgFoundry contributed. PostgreSQL sine intervall-datatyper støttes av mange innebygde operatorer og funksjoner.
* Teradata versjon 13.10 og Teradata versjon 14 har temporale funksjoner basert på TSQL2 innebygd i databasen.
* IBM Db2 versjon 10 la til en funksjon som heter "time travel query" som er basert på de temporale kapabilitetene til -standarden.
* Microsoft SQL Server la til temporale tabeller som en funksjon i SQL Server 2016. Funksjonen er beskrevet i en video på Microsofts nettsted "Channel 9".

Ikke-relasjonelle, NoSQL-databasesystemer som har temporale funksjoner inkluderer:

* TerminusDB er en fullverdig åpen kildekodet grafdatabase som ut av boksen støtter versjonskontroll, tidsreise-spørringer og diff-funksjoner. Den har en uforanderlig (immuterbar) lagarkitektur basert på deltaenkoding og kortfattede datastrukturer.
* MarkLogic la til bitemporal datastøtte i versjon 8.0. Tidsstempler for gyldigtid og Systemtid lagres i JSON eller XML-dokumenter.
* SirixDB lagrer øyeblikksbilder (*snapshots*) av XML- og JSON-dokumenter veldig effektivt i binært format på grunn av en ny versjonsalgoritme kalt glidende øyeblikksbilde (*sliding snapshot*), som balanserer lese-/skriveytelse og aldri skaper skrivetopper. Tidsreise-spørringer og diffunksjoner støttes ut av boksen.
* XTDB (tidligere Crux) gir bitemporale tidspunkts-spørringer (*point in time queries*) ved hjelp av språket Datalog om transaksjoner og dokumenter tatt inn (*ingested*) fra semi-uforanderlige Kafka-logger. Dokumenter indekseres automatisk for å opprette entitet-attributt-verdi modell-indekser uten krav til å definere et skjema. Transaksjonsoperasjoner angir effektive gyldigtider. Transaksjonstider tildeles av Kafka og muliggjør horisontal skalerbarhet via konsistent lesing.
* RecallGraph er et tidspunkts- (*point in time*), unitemporal (transaksjonstids-) grafdatabase bygget på toppen av ArangoDB. Den kjører på ArangoDB Foxx Microservice undersystem. Den har versjonskontroll-lignende semantikk i mange deler av grensesnittet, og støttes av en transaksjonell hendelsesporer. Bitemporalitet er angitt et utviklingsmål.

Temporale databaser var en av de tidligste formene for dataversjonskontroll, og påvirket utviklingen av moderne dataversjoneringssystemer.

### Alternativer

Endringstreg dimensjoner kan brukes til å modellere temporale relasjoner.
 

## Se også
* Ankermodellering
* Databaseteori
* Hendelseslager
* Romlig-temporal database
* Tidsseriedatabase
* Verdiområde

## Referanser