Views, transaksjoner, integritet
Logiske abstraksjoner over data, regler som forhindrer tull, og syntaksen som binder flere endringer sammen i én atomær enhet.
Lagrede spørringer som virtuelle tabeller
En view er en navngitt SELECT. Den oppfører seg som en tabell — du kan velge fra den, joine den, lage views over views — men dataene ligger i de underliggende tabellene. Views er kraftige fordi de gir to ting: (1) gjenbrukbar kompleksitet og (2) en sikkerhetsmekanisme der brukere får se en utsnitt uten å få tilgang til hele basen.
CREATE VIEW faculty AS
SELECT ID, name, dept_name
FROM instructor;
-- Brukes som en helt vanlig tabell:
SELECT name FROM faculty WHERE dept_name = 'Biology';
Virtuell vs. materialisert
Hvorfor views?
- Forenkling — pakk en kompleks join inn i ett navn.
- Sikkerhet — gi en bruker tilgang til viewet, ikke basetabellen, så de bare ser delen som er relevant for dem.
- Logisk uavhengighet — endre underliggende skjema, men behold viewets «kontrakt» mot applikasjonen.
Når kan du INSERT/UPDATE/DELETE gjennom et view?
Et view er oppdaterbart hvis SQL kan unikt avgjøre hvilken endring i basetabellene som skal foretas. Det er strenge regler:
- Kun én tabell i FROM (ingen joins).
- Ingen aggregat / GROUP BY / HAVING / DISTINCT (de slår sammen rader — kan ikke inverteres).
- Alle NOT NULL-kolonner uten DEFAULT må være med i SELECT-listen — ellers kan vi ikke INSERT-e.
- Ingen aritmetikk eller subqueries i SELECT-listen.
WITH CHECK OPTION
Et viktig sikkerhetsnett: viewet definerer en filtrert visning, men brukeren kan likevel sette inn rader som havner utenfor viewet — og da forsvinner de fra deres syn. WITH CHECK OPTION hindrer dette.
CREATE VIEW cs_instructor AS
SELECT *
FROM instructor
WHERE dept_name = 'CS'
WITH CHECK OPTION;
-- Forsøk på å sette inn en Physics-ansatt gjennom dette viewet
-- vil avvises — raden ville ikke vært synlig i viewet etterpå.
INSERT INTO cs_instructor VALUES ('9999', 'X', 'Physics', 50000);
-- ERROR: violates view check option
Reglene som beskytter dataene
Constraints er kontrakter mellom skjemaet og hver INSERT/UPDATE. DBMS-en avviser endringer som bryter dem — uten dem ville dårlig data sive inn umerket.
| Type | Hvor | Hva det sikrer |
|---|---|---|
NOT NULL | Kolonne | Verdien er obligatorisk |
UNIQUE (a, b) | Kolonnegruppe | Kombinasjonen er entydig (NULL-verdier kan unntas) |
PRIMARY KEY (k) | Tabell | Unik + NOT NULL — én per tabell |
FOREIGN KEY (k) REFERENCES r | Tabell | Refereransenintegritet — k må finnes i r |
CHECK (uttrykk) | Kolonne / tabell | Vilkårlig predikat per rad |
CREATE TABLE account (
acct_no VARCHAR(10) PRIMARY KEY,
branch VARCHAR(20) NOT NULL,
balance NUMERIC(12, 2) CHECK (balance >= 0),
customer VARCHAR(10) NOT NULL,
FOREIGN KEY (customer) REFERENCES customer (id),
UNIQUE (branch, customer)
);
Hva skjer med referanser når den refererte raden forsvinner?
Når en rad i den refererte tabellen slettes eller endres, kan referansen i den refererende tabellen behandles på fire måter:
CREATE TABLE course (
course_id VARCHAR(7) PRIMARY KEY,
dept_name VARCHAR(20),
FOREIGN KEY (dept_name) REFERENCES department (dept_name)
ON DELETE SET NULL
ON UPDATE CASCADE
);
Eksemplet: hvis en avdeling slettes, blir kursenes dept_name satt til NULL. Hvis avdelingsnavnet endres, oppdateres alle referanser automatisk.
FOREIGN KEY (kunde_id) REFERENCES kunde ON DELETE CASCADE. En kunde slettes. Hva skjer?Egendefinerte regler
CHECK — per rad
CREATE TABLE employee (
id INT PRIMARY KEY,
age INT CHECK (age BETWEEN 16 AND 100),
salary NUMERIC(10, 2),
bonus NUMERIC(10, 2),
CHECK (bonus <= salary / 2)
);
CHECK-er evalueres ved hver INSERT/UPDATE. Begrensning: de gjelder per rad — du kan referere til andre kolonner i samme rad, men ikke andre rader eller andre tabeller (i ANSI-standarden; noen DBMS-er løsner på dette).
ASSERTION — på databasen
Dette er regler som spenner over flere rader/tabeller. Standard SQL definerer CREATE ASSERTION, men det er nesten ingen DBMS som implementerer det — fordi systemet må sjekke regelen ved hver eneste endring som kunne brutt den.
-- ANSI-standard, sjeldent støttet i praksis
CREATE ASSERTION total_credits_check
CHECK (
NOT EXISTS (
SELECT ID FROM student
WHERE tot_cred > 200
)
);
I praksis må regler på tvers av rader/tabeller implementeres med triggere (se 3D).
BEGIN · COMMIT · ROLLBACK
En transaksjon er en sekvens av SQL-setninger som behandles som én atomær enhet — alt eller ingenting. Den klassiske eksempelet er en bankoverføring: trekk fra konto A og legg til på konto B må enten begge skje, eller ingen.
BEGIN TRANSACTION;
UPDATE account SET balance = balance - 500
WHERE acct_no = 'A-101';
UPDATE account SET balance = balance + 500
WHERE acct_no = 'B-202';
COMMIT;
-- eller, ved feil:
-- ROLLBACK;
Atomicity (alt eller ingenting) · Consistency (databasen må alltid følge constraints) · Isolation (samtidige transaksjoner skal ikke se hverandres halvferdige tilstander) · Durability (commit overlever krasj). Den fulle teorien dekkes i kapittel 8.
SAVEPOINT — delvis rollback
BEGIN;
INSERT INTO a VALUES (1);
SAVEPOINT s1;
INSERT INTO a VALUES (2);
ROLLBACK TO s1; -- 2 rulles tilbake, 1 består
COMMIT;
Isolation levels
SET TRANSACTION ISOLATION LEVEL … styrer hvor strengt isolert transaksjonen din er fra andre samtidige. Standardenes valg:
| Nivå | Forhindrer | Tillater |
|---|---|---|
| READ UNCOMMITTED | — | Dirty reads (les ucommittet) |
| READ COMMITTED | Dirty reads | Non-repeatable reads, phantoms |
| REPEATABLE READ | Dirty + non-repeatable | Phantoms |
| SERIALIZABLE | Alle tre | Strengeste — laveste samtidighet |
Få fart på spørringer
En indeks er en datastruktur (typisk B+-tre) som lar DBMS-en finne rader uten å lese hele tabellen. Selve datastrukturen dekkes i kapittel 6 — her dreier det seg om hvordan du definerer dem i SQL.
-- Enkel indeks
CREATE INDEX idx_inst_name ON instructor (name);
-- Sammensatt — rekkefølgen er signifikant!
CREATE INDEX idx_dept_sal ON instructor (dept_name, salary);
-- Unik indeks — håndhever entydighet
CREATE UNIQUE INDEX idx_email ON users (email);
DROP INDEX idx_inst_name;
En indeks gjør SELECT raskere, men gjør INSERT, UPDATE og DELETE tregere — fordi indeksen også må vedlikeholdes. Indekser «gratis» finnes ikke. Velg dem ut fra hvilke spørringer som faktisk er hot path i applikasjonen din.
Sammensatte indekser: hvorfor rekkefølgen betyr noe
En indeks på (dept_name, salary) kan brukes for WHERE dept_name = 'CS', men ikke alene for WHERE salary > 70000. Tenk på det som et sortert leksikon: du finner kjapt alle CS-ansatte, men ikke alle med en gitt lønn — fordi de er sortert etter avdeling først.
Hvem får gjøre hva?
GRANT SELECT, INSERT ON instructor TO alice, bob;
GRANT UPDATE (salary) ON instructor TO hr_app;
GRANT SELECT ON faculty TO public;
REVOKE INSERT ON instructor FROM bob;
Privilegier i SQL-standarden
SELECT·INSERT·UPDATE·DELETE— på tabell eller viewREFERENCES— lov til å lage FK-er som peker på tabellenALL PRIVILEGES— alle de over
WITH GRANT OPTION
GRANT SELECT ON instructor TO alice WITH GRANT OPTION;
-- Alice kan nå GRANT SELECT videre til andre.
-- Når du REVOKE-er fra Alice, faller hele kjeden hun ga videre.
Roller
I store systemer blir det uhåndterbart å gi privilegier per bruker. Roller er navngitte samlinger av privilegier. Tildel rollen til brukere, så har de alle privilegiene rollen har — og endringen sprer seg automatisk.
CREATE ROLE teacher;
GRANT SELECT, UPDATE ON grades TO teacher;
GRANT teacher TO alice, bob, carol;
GRANT SELECT ON t TO alice WITH GRANT OPTION. Hun gir GRANT SELECT ON t TO bob. Senere REVOKE-er DBA-en hennes privilegium fra Alice. Hva skjer med Bobs tilgang?CASCADE nøkkelord; andre bruker RESTRICT som default.Det du skal kunne
- Skrive
CREATE VIEWog forklare når et view er oppdaterbart. - Bruke
WITH CHECK OPTIONog forklare hva det forhindrer. - Liste de fire ON DELETE-handlingene og når CASCADE er passende.
- Skille CHECK fra ASSERTION og vite hvorfor sistnevnte sjeldent brukes.
- Skrive en transaksjon med BEGIN/COMMIT/ROLLBACK og forklare ACID.
- Designe en sammensatt indeks slik at WHERE-klausulen kan bruke den.
- Bruke GRANT/REVOKE og forklare cascading revoke.
Klar for prosedyrer, triggere og rekursjon? Gå til 3D →