SQL Academy · Les

Tijdelijke en versiebeheerste rijen

Query's op geldige tijd en op een bepaald tijdstip

Les 3 van 413 stappen

Tijdelijke en versiebeheerste rijen is een gratis SQL Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject SQL Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus SQL Academy bevat in totaal 4 lessen.

Wat zijn temporele tabellen?

Met temporele tabellen kun je volgen hoe gegevens in de loop van de tijd veranderen. In plaats van een rij bij een wijziging te overschrijven, bewaart een temporele tabel elke versie van die rij, voorzien van de periode waarin die versie geldig was.

Er zijn twee belangrijke concepten: geldigheidstijd (wanneer het feit in de echte wereld waar was) en transactietijd (wanneer de database het feit heeft vastgelegd). Door beide te combineren, krijg je een volledig bitemporele tabel.

Geldigheidstijd versus transactietijd

Geldigheidstijd geeft aan wanneer een feit in de echte wereld waar is — bijvoorbeeld het salaris van een werknemer van 2020-01-01 tot 2022-06-30. Transactietijd is het moment waarop de database de rij invoegde of ongeldig verklaarde. Samen beantwoorden ze twee vragen: Wat was waar? en Wanneer wisten we dat?

De meeste praktische toepassingen beginnen met het bijhouden van geldigheidstijd. Dat kun je handmatig implementeren met de kolommen valid_from en valid_to.

Een tabel met geldigheidstijd maken

De eenvoudigste manier om versiebeheerste rijen op te slaan, is het toevoegen van tijdstempelkolommen valid_from en valid_to. Een waarde NULL voor valid_to (of een speciale verre-toekomstwaarde zoals 9999-12-31) betekent dat de rij momenteel actief is.

CREATE TABLE employee_salary (
  id          SERIAL PRIMARY KEY,
  employee_id INT NOT NULL,
  salary      NUMERIC(12, 2) NOT NULL,
  valid_from  DATE NOT NULL,
  valid_to    DATE
);

INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES
  (1, 50000, '2020-01-01', '2022-06-30'),
  (1, 60000, '2022-07-01', NULL);

De huidige versie opvragen

Om de momenteel actieve rij voor elke werknemer te vinden, filter je op rijen waarvoor valid_to IS NULL geldt (zonder einddatum), of waarop de datum van vandaag binnen het geldigheidsbereik valt. Een speciale waarde zoals '9999-12-31' maakt vergelijkingen van bereiken eenvoudiger.

SELECT employee_id, salary
FROM employee_salary
WHERE valid_to IS NULL
ORDER BY employee_id;

Query's voor een bepaald moment

Een query voor een bepaald moment vraagt: Hoe zagen de gegevens er op een specifiek moment uit? Je filtert op rijen waarvan de opgegeven tijdstempel binnen de geldigheidsperiode valt. Dit is een van de krachtigste functies van temporele tabellen.

-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_from, valid_to
FROM employee_salary
WHERE employee_id = 1
  AND valid_from <= '2021-03-15'
  AND (valid_to IS NULL OR valid_to > '2021-03-15');

Een versiebeheerste rij bijwerken

Wanneer een feit verandert, voer je niet rechtstreeks een UPDATE uit op de bestaande rij. In plaats daarvan sluit je de huidige rij door de waarde van valid_to in te stellen en voeg je een nieuwe rij met de nieuwe waarde in met INSERT. Zo blijft de volledige geschiedenis behouden.

-- Employee 1 gets a raise effective 2023-01-01
BEGIN;

-- Close the current open row
UPDATE employee_salary
SET valid_to = '2022-12-31'
WHERE employee_id = 1
  AND valid_to IS NULL;

-- Insert the new version
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES (1, 72000, '2023-01-01', NULL);

COMMIT;

daterange gebruiken voor geldigheidsperioden

Het PostgreSQL-type daterange modelleert een geldigheidsperiode op elegante wijze in één kolom. Je kunt de operator @> (bevat) gebruiken om te controleren of een datum binnen het bereik valt en een uitsluitingsbeperking toevoegen om overlappende perioden voor dezelfde entiteit te voorkomen.

CREATE TABLE employee_salary_v2 (
  id          SERIAL PRIMARY KEY,
  employee_id INT NOT NULL,
  salary      NUMERIC(12, 2) NOT NULL,
  valid_period DATERANGE NOT NULL,
  EXCLUDE USING GIST (employee_id WITH =, valid_period WITH &&)
);

INSERT INTO employee_salary_v2 (employee_id, salary, valid_period)
VALUES
  (1, 50000, '[2020-01-01, 2022-07-01)'),
  (1, 60000, '[2022-07-01, infinity)');

Query voor een bepaald moment met daterange

Met de aanpak op basis van daterange wordt de query voor een bepaald moment zeer leesbaar. De operator @> controleert of de opgegeven datum binnen het bereik valt en verwerkt de onder- en bovengrens automatisch.

-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_period
FROM employee_salary_v2
WHERE employee_id = 1
  AND valid_period @> '2021-03-15'::date;

Door het systeem geversioneerde tabellen (SQL-standaard)

De SQL:2011-standaard introduceerde systeemgeversioneerde temporele tabellen. De database beheert automatisch de transactietijdkolommen row_start en row_end. In PostgreSQL boots je dit na; in SQL Server en MariaDB is het ingebouwd met SYSTEM VERSIONING.

Het onderstaande voorbeeld toont de syntaxis van SQL Server en MariaDB als verwijzing naar het concept.

-- SQL Server / MariaDB syntax (reference)
CREATE TABLE dbo.Product (
  ProductID   INT PRIMARY KEY,
  Name        VARCHAR(100),
  Price       DECIMAL(10,2),
  SysStart    DATETIME2 GENERATED ALWAYS AS ROW START,
  SysEnd      DATETIME2 GENERATED ALWAYS AS ROW END,
  PERIOD FOR SYSTEM_TIME (SysStart, SysEnd)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Product_History));

Tijdgebonden koppelingen: twee tabellen op tijd uitlijnen

Een veelvoorkomende uitdaging is het koppelen van twee temporele tabellen op overeenkomende tijdsperioden. Denk bijvoorbeeld aan het koppelen van salarissen van werknemers aan afdelingsindelingen wanneer beide geldigheidsperioden hebben. Je koppelt op entiteitssleutel EN overlappingsvoorwaarde met && voor bereiken, of met expliciete datumvergelijkingen.

CREATE TABLE dept_assignment (
  employee_id INT,
  department  VARCHAR(50),
  valid_period DATERANGE
);

INSERT INTO dept_assignment VALUES
  (1, 'Engineering', '[2020-01-01, infinity)'),
  (1, 'Marketing',   '[2019-01-01, 2020-01-01)');

-- Periods where employee 1 was in Engineering AND had salary > 55000
SELECT s.salary, d.department,
       s.valid_period * d.valid_period AS overlap_period
FROM employee_salary_v2 s
JOIN dept_assignment d
  ON s.employee_id = d.employee_id
  AND s.valid_period && d.valid_period
WHERE s.employee_id = 1
  AND s.salary > 55000;

Hiaten en overlappingen voorkomen

Twee veelvoorkomende problemen met de gegevenskwaliteit in temporele tabellen zijn hiaten (perioden zonder record) en overlappingen (twee rijen die gelijktijdig geldig zijn). De uitsluitingsbeperking met && voorkomt overlappingen op databaseniveau. Voor het detecteren van hiaten moet je met een query controleren of er ontbrekende dekking is.

-- Find gaps in salary history for employee 1
-- (periods where upper(prev) < lower(next))
SELECT
  upper(a.valid_period) AS gap_start,
  lower(b.valid_period) AS gap_end
FROM employee_salary_v2 a
JOIN employee_salary_v2 b
  ON a.employee_id = b.employee_id
  AND upper(a.valid_period) < lower(b.valid_period)
WHERE a.employee_id = 1
  AND NOT EXISTS (
    SELECT 1 FROM employee_salary_v2 c
    WHERE c.employee_id = 1
      AND lower(c.valid_period) > upper(a.valid_period)
      AND lower(c.valid_period) < lower(b.valid_period)
  )
ORDER BY gap_start;

Kennistoets

Test je kennis van temporele tabellen en query's voor een bepaald moment.

Samenvatting: temporele en versiebeheerste rijen

In deze les heb je geleerd hoe je tijdsafhankelijke gegevens modelleert met kolommen voor geldigheidstijd en het PostgreSQL-type daterange. Belangrijkste punten:

  • Historische rijen nooit overschrijven — sluit de oude rij af en voeg een nieuwe versie in.
  • Gebruik query's voor een bepaald moment (valid_from <= target AND valid_to > target) om gegevens op elk moment in het verleden op te vragen.
  • Het type daterange met de operator @> maakt query's voor tijdsgegevens beknopt en leesbaar.
  • Uitsluitingsbeperkingen op && (overlap van bereiken) waarborgen de gegevensintegriteit op databaseniveau.
  • Tijdgebonden koppelingen brengen twee geschiedenissen met elkaar in lijn door hun geldigheidsperioden te kruisen.

Deze patronen vormen de basis van event sourcing, auditregistratie en elk systeem waarin historische nauwkeurigheid belangrijk is.

Gratis beginnen

Leer SQL met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
46
Lessen
183

Veelgestelde vragen

Is de les “Tijdelijke en versiebeheerste rijen” gratis?

Ja — de volledige tekst van “Tijdelijke en versiebeheerste rijen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus SQL Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus SQL Academy bevat in totaal 4 lessen.

Wat leer ik in “Tijdelijke en versiebeheerste rijen”?

Query's op geldige tijd en op een bepaald tijdstip Je oefent met SQL Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met SQL Academy te beginnen?

Ervaring vooraf is niet nodig. SQL Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “Tijdelijke en versiebeheerste rijen”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over SQL Academy?

Ja. Elke les over SQL Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Waarom geschiedenis bewaren
  2. Eventtabellen met alleen toevoegingen
  3. Tijdelijke en versiebeheerste rijen
  4. Status opnieuw opbouwen uit events
← Terug naar SQL Academy