SQL Academy · leksjon

Hvorfor ta vare på historikken

Revisjon, angre og analyse av fortiden.

Leksjon 1 av 413 trinn

Hvorfor ta vare på historikken er en gratis leksjon i SQL Academy på CoddyKit. Dette er leksjon 1 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i SQL Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i SQL Academy inneholder totalt 4 leksjoner.

Problemet med å overskrive data

Hver gang du kjører UPDATE eller DELETE, forsvinner de gamle dataene for godt. Det høres effektivt ut, men skaper reelle problemer: Du kan ikke svare på spørsmål som hva var prisen forrige tirsdag? eller hvem endret denne posten, og når?

Å ta vare på historikken betyr å lagre hver versjon av en rad, ikke bare den nyeste. I denne leksjonen utforsker du hvorfor dette er viktig, og hvordan SQL hjelper deg med å gjøre det.

Tre grunner til å ta vare på historikken

Det finnes tre klassiske grunner til å bevare historiske data i en database:

1. Revisjon – dokumenter at en endring fant sted, hvem som gjorde den, og når.
2. Angring – rull tilbake en feil uten å gjenopprette hele databasen.
3. Analyse – svar på spørsmål om fortiden, oppdag trender og sammenlign perioder.

En godt utformet strategi for historikk dekker alle tre behovene uten å bruke unødvendig mye lagringsplass på duplikater.

En enkel revisjonstabell

Den enkleste fremgangsmåten er en separat revisjonstabell som registrerer hver endring. Hver rad inneholder den gamle verdien, den nye verdien, hvem som gjorde endringen, og når.

Nedenfor ser du en revisjonstabell for tabellen products. Kolonnen operation lagrer INSERT, UPDATE eller DELETE.

CREATE TABLE products_audit (
  audit_id   SERIAL PRIMARY KEY,
  product_id INT            NOT NULL,
  operation  VARCHAR(6)     NOT NULL,  -- INSERT / UPDATE / DELETE
  old_price  NUMERIC(10,2),
  new_price  NUMERIC(10,2),
  changed_by TEXT           NOT NULL,
  changed_at TIMESTAMPTZ    NOT NULL DEFAULT NOW()
);

Fylle ut revisjonstabellen

Du kan skrive til en revisjonstabell manuelt, men den mest pålitelige fremgangsmåten er en databasetrigger som utløses automatisk hver gang data endres. På denne måten kan ingen applikasjonskode omgå loggen.

Her setter vi inn én revisjonsrad direkte for å illustrere strukturen før vi går gjennom triggere.

INSERT INTO products_audit (product_id, operation, old_price, new_price, changed_by)
VALUES (42, 'UPDATE', 9.99, 12.49, 'alice');

SELECT * FROM products_audit ORDER BY changed_at DESC LIMIT 5;

Lese revisjonssporet

Når det har samlet seg rader i revisjonstabellen, kan du spørre i den for å besvare spørsmål om revisjon. Spørringen nedenfor viser hele prishistorikken for ett produkt, med den nyeste først.

SELECT
  changed_at,
  changed_by,
  operation,
  old_price,
  new_price
FROM products_audit
WHERE product_id = 42
ORDER BY changed_at DESC;

Gyldighetsdatoer: historikk basert på gyldighetstid

En revisjonstabell registrerer når du gjorde endringen (transaksjonstid). Noen ganger må du også spore når noe faktisk var sant i virkeligheten – dette kalles gyldighetstid.

Ved å legge til kolonnene valid_from og valid_to i hovedtabellen oppretter du historikk basert på gyldighetstid, også kalt en dimensjon som endres sakte (SCD Type 2).

CREATE TABLE employee_history (
  id          SERIAL PRIMARY KEY,
  employee_id INT            NOT NULL,
  department  TEXT           NOT NULL,
  salary      NUMERIC(10,2)  NOT NULL,
  valid_from  DATE           NOT NULL,
  valid_to    DATE           -- NULL means current record
);

-- Current record for employee 7
INSERT INTO employee_history (employee_id, department, salary, valid_from)
VALUES (7, 'Engineering', 85000, '2023-01-01');

Oppdatere en post som endres sakte

Når en ansatt bytter avdeling, oppdaterer du ikke raden med UPDATE. I stedet avslutter du den gamle raden ved å angi valid_to og setter inn en ny rad uten sluttdato. På denne måten bevarer du hele historikken.

-- Step 1: close the current record
UPDATE employee_history
SET valid_to = '2024-06-01'
WHERE employee_id = 7 AND valid_to IS NULL;

-- Step 2: insert the new record
INSERT INTO employee_history (employee_id, department, salary, valid_from)
VALUES (7, 'Product', 90000, '2024-06-01');

-- Verify history
SELECT department, salary, valid_from, valid_to
FROM employee_history
WHERE employee_id = 7
ORDER BY valid_from;

Spørre på et bestemt tidspunkt

Med kolonner for gyldighetstid kan du spørre hva som var sant på en bestemt dato – noe som ikke ville vært mulig med en vanlig UPDATE-modell.

WHERE-klausulen kontrollerer at måldatoen faller innenfor radens gyldighetsintervall.

-- What department and salary did employee 7 have on 2023-09-15?
SELECT department, salary, valid_from, valid_to
FROM employee_history
WHERE employee_id = 7
  AND valid_from <= '2023-09-15'
  AND (valid_to > '2023-09-15' OR valid_to IS NULL);

Systemversjonerte temporale tabeller

Moderne SQL-databaser (PostgreSQL 16+, SQL Server, MySQL 8) støtter systemversjonerte temporale tabeller. Databasen sporer automatisk transaksjonstid i skjulte kolonner, og du kan spørre etter tidligere tilstander med en spesiell syntaks.

Eksempel fra SQL Server – konseptet er det samme på tvers av databasemotorer:

-- SQL Server / MariaDB style (illustrative)
CREATE TABLE orders (
  order_id    INT PRIMARY KEY,
  status      VARCHAR(20),
  total       NUMERIC(10,2),
  SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START,
  SysEndTime   DATETIME2 GENERATED ALWAYS AS ROW END,
  PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
) WITH (SYSTEM_VERSIONING = ON);

-- Query historical state
SELECT * FROM orders FOR SYSTEM_TIME AS OF '2024-01-15 12:00:00'
WHERE order_id = 100;

Bruke historikk til å angre

Historikktabeller er ikke bare til lesing – de kan brukes til å angre feil. Hvis en batchjobb ødela 500 prisoppføringer, kan du gjenopprette dem fra audit-tabellen uten å røre en sikkerhetskopi.

-- Undo all price changes made by the bad batch job at a specific time
UPDATE products p
SET price = a.old_price
FROM products_audit a
WHERE p.id         = a.product_id
  AND a.operation  = 'UPDATE'
  AND a.changed_by = 'batch_job'
  AND a.changed_at BETWEEN '2024-03-10 02:00:00' AND '2024-03-10 02:05:00';

-- Confirm affected rows
SELECT COUNT(*) AS rows_restored FROM products_audit
WHERE changed_by = 'batch_job'
  AND changed_at BETWEEN '2024-03-10 02:00:00' AND '2024-03-10 02:05:00';

Analyse over tid

Historikkdata åpner for tidsserieanalyser. Du kan følge med på hvordan et mål utvikler seg, sammenligne tall fra måned til måned eller oppdage avvik – alt uten å berøre et separat datavarehus.

Denne spørringen viser gjennomsnittsprisen for et produkt i hver kalendermåned ved hjelp av audit-tabellen.

SELECT
  DATE_TRUNC('month', changed_at) AS month,
  ROUND(AVG(new_price), 2)         AS avg_price
FROM products_audit
WHERE product_id = 42
  AND operation IN ('INSERT', 'UPDATE')
GROUP BY 1
ORDER BY 1;

Kunnskapstest

Test forståelsen din av lagring av historiske data i SQL.

Oppsummering: Hvorfor bevare historikk

I denne leksjonen lærte du hvorfor det er risikabelt å overskrive data, og hvordan SQL-mønstre bevarer historikk for revisjon, angreoperasjoner og analyse.

Viktigste punkter:

  • Audit-tabeller loggfører alle INSERT-, UPDATE- og DELETE-operasjoner, med hvem som utførte dem og når.
  • Rader med valid time (SCD Type 2) bruker kolonnene valid_from / valid_to til å registrere tidsforløp i den virkelige verden.
  • Point-in-time-spørringer besvarer historiske spørsmål ved å filtrere på disse datokolonnene.
  • Systemversjonerte temporale tabeller automatiserer sporing av transaction time på databasenivå.
  • Historikkdata muliggjør målrettede angreoperasjoner og avanserte tidsserieanalyser uten behov for sikkerhetskopier.

Å bevare fortiden er ikke unødvendig overhead – det er grunnlaget for pålitelige systemer som kan revideres.

Gratis å komme i gang

Lær deg SQL med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
46
Leksjoner
183

Ofte stilte spørsmål

Er leksjonen «Hvorfor ta vare på historikken» gratis?

Ja – hele teksten i «Hvorfor ta vare på historikken» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av SQL Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i SQL Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Hvorfor ta vare på historikken»?

Revisjon, angre og analyse av fortiden. Du øver på SQL Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med SQL Academy?

Ingen tidligere erfaring er nødvendig. SQL Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Hvorfor ta vare på historikken»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne SQL Academy-leksjonen?

Ja. Alle SQL Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Hvorfor ta vare på historikken
  2. Hendelsestabeller med kun tillegg
  3. Temporale og versjonerte rader
  4. Gjenoppbygge tilstand fra hendelser
← Tilbake til SQL Academy