Kapittel 3 · 3A · Forelesning 3 · Lærebok 3.1–3.7, 3.9

SQL — DDL og spørringer

Tabeller, SELECT, aggregat — hovedmotet i SQL. Vi går fra «tom database» til en spørring som svarer på et faktisk spørsmål, og lærer fellene underveis.

01 · DDL

CREATE TABLE og typer

Et relasjonsskjema er en kontrakt: hvilke kolonner finnes, hvilke typer har de, og hvilke rad-kombinasjoner er ulovlige. SQL DDL-en lar deg spesifisere alt dette i én setning. Eksemplet under er hentet fra universitetsdatabasen i lærebokens figur 3.1.

CREATE TABLE department (
  dept_name  VARCHAR(20),
  building   VARCHAR(15),
  budget     NUMERIC(12, 2),
  PRIMARY KEY (dept_name)
);

CREATE TABLE course (
  course_id  VARCHAR(7),
  title      VARCHAR(50),
  dept_name  VARCHAR(20),
  credits    NUMERIC(2, 0),
  PRIMARY KEY (course_id),
  FOREIGN KEY (dept_name) REFERENCES department
);

Datatyper du må kjenne

TypeBeskrivelseEksempel
CHAR(n)Fast lengde — padder med blanke. Vær varsom: 'Avi' blir 'Avi       ' i CHAR(10).CHAR(2) for landskode
VARCHAR(n)Variabel lengde opp til n. Foretrukket for tekst.VARCHAR(50) for navn
INT / SMALLINTHeltall, maskinavhengig størrelse.INT for antall
NUMERIC(p, d)Eksakt desimaltall: p totale sifre, d etter desimaltegnet.NUMERIC(12,2) for valuta
REAL / DOUBLE PRECISIONFlyttall — bruk når presisjon er mindre kritisk.Sensordata
DATE / TIMESTAMPDato eller dato + klokkeslett (med eller uten tidssone).DATE '2026-04-26'
Praksisregel

Bruk VARCHAR over CHAR. Sammenligning av CHAR og VARCHAR oppfører seg ulikt på tvers av DBMS — det fører til subtile bugger der A = B overraskende returnerer false fordi A er padded.

Integritetskrav på rad-nivå

  • NOT NULL — feltet kan ikke være tomt
  • PRIMARY KEY (a, b, …) — entydig identifikator, implisitt NOT NULL
  • FOREIGN KEY (a) REFERENCES s — verdien må finnes i tabell s's primærnøkkel
  • UNIQUE (a, b) — kombinasjonen må være entydig (men kan være NULL i noen DBMS)
  • CHECK (uttrykk) — predikat på kolonne eller rad

Endre og slette skjema

Legge til kolonne
ALTER TABLE instructor
  ADD phone VARCHAR(15);
Effekt
-- Alle eksisterende rader får
-- phone = NULL
DROP TABLE r
Sletter både skjema og data — irreversibelt.
DELETE FROM r
Tømmer rader, beholder skjemaet.
TRUNCATE r
Som DELETE, men raskere og uten transaksjonsspor (DBMS-spesifikt).
ALTER TABLE
Legg til/fjern kolonner, endre constraints, omdøp tabellen.
Sjekkpunkt · Lett
Du oppretter CREATE TABLE x (id INT PRIMARY KEY, parent_id INT, FOREIGN KEY (parent_id) REFERENCES x);. Deretter prøver du å sette inn INSERT INTO x VALUES (1, 1);. Hva skjer?
Selvreferansen er klassisk for hierarki (ansatt → leder, kategori → forelder). Klassen som ofte feiler i quiz er at første rot-rad må sette parent_id til seg selv eller kreves at FK tillater NULL.
02 · SELECT-grunnform

SELECT — projeksjon, kilde, filter

Tre obligatoriske komponenter: SELECT (hvilke kolonner), FROM (fra hvilke relasjoner), WHERE (hvilke rader). Tenk på dem som π, × og σ i relasjonsalgebra-termer.

Eksempel: enkel én-tabell-spørring

SQL
SELECT name
FROM instructor
WHERE dept_name = 'Comp. Sci.'
  AND salary > 70000;
Resultat
name
Katz
Brandt

Aritmetikk og aliaser

SELECT kan inneholde uttrykk: + − * / og funksjonskall. Bruk AS for å gi et lesbart navn til resultat-kolonnen.

SQL
SELECT ID, name,
       salary AS dagens,
       salary * 1.1 AS etter_paaslag
FROM instructor;
Resultat (utdrag)
IDnamedagensetter_paaslag
10101Srinivasan6500071500.00
22222Einstein95000104500.00
15151Mozart4000044000.00

Flere tabeller — kartesisk produkt + filter

Når FROM har flere relasjoner, bygger SQL først det kartesiske produktet og deretter filtrerer med WHERE. Dette er den mentale modellen — ikke nødvendigvis hva motoren faktisk gjør.

INSTRUCTOR ID name 10101 Srinivasan 22222 Einstein 15151 Mozart TEACHES ID course_id 10101 CS-101 22222 PHY-101 10101 CS-315 FROM × FROM (3·3=9 RADER) i.ID name t.ID course 10101Srinivasan10101CS-101 10101Srinivasan22222PHY-101 10101Srinivasan10101CS-315 22222Einstein10101CS-101 22222Einstein22222PHY-101 22222Einstein10101CS-315 15151Mozart 10101CS-101 15151Mozart 22222PHY-101 15151Mozart 10101CS-315 3 av 9 rader oppfyller WHERE i.ID = t.ID Steg 1: To kildetabeller
Klikk gjennom de tre stegene. Husk: dette er den logiske evalueringen; en moderne optimaliserer vil aldri faktisk lage hele det kartesiske produktet hvis den ikke må.
Steg 1 / 3
Med tall

Med 200 ansatte som hver underviser i 3 emner får du 200·600 = 120 000 rader i mellomresultatet. Bare riktig WHERE redder ytelsen — eller en optimalisator som er smart nok til å unngå hele produktet.

03 · WHERE og NULL

Filtrer rader — og unngå NULL-fellen

Operatorer du har

Sammenligning
= <> < > <= >=
BETWEEN
x BETWEEN a AND bx >= a AND x <= b
IN / NOT IN
dept_name IN ('CS','EE')
LIKE
Strengmønster med % og _
IS NULL
Eneste lovlige test for fravær
AND / OR / NOT
Logiske koblinger — gir tre-verdi-logikk

Tre-verdi-logikk: TRUE, FALSE, UNKNOWN

I SQL er NULL ikke en verdi du sammenligner mot — det er en markør for «ukjent eller fraværende». Sammenligning med NULL gir alltid UNKNOWN, og WHERE beholder kun rader der predikatet er TRUE.

UttrykkResultatHvorfor
5 = NULLUNKNOWNVi vet ikke om x er 5
NULL = NULLUNKNOWNTo ukjente verdier kan være like — eller ikke
x IS NULLTRUE / FALSESpør om fravær, ikke om verdi-likhet
NULL AND TRUEUNKNOWNHvis vi visste, kunne vært TRUE eller FALSE
NULL OR TRUETRUEOR med TRUE er alltid TRUE — uansett
NULL AND FALSEFALSEAND med FALSE er alltid FALSE
Klassisk feller

WHERE x <> 5 returnerer ikke rader hvor x er NULL. Hvis du vil ha «alt unntatt 5, inkludert ukjente», skriv WHERE x <> 5 OR x IS NULL.

Sjekkpunkt · Middels
Tabellen t(x) har radene {1, 2, NULL, 5}. Hvor mange rader returnerer SELECT x FROM t WHERE x <> 5;?
NULL <> 5 er UNKNOWN, ikke TRUE. WHERE filtrerer den bort. Bare 1 og 2 består.
04 · Strenger og LIKE

Tekstmønstre med LIKE

Strenger skrives i enkelt-fnutter: 'Computer'. Et fnutt-tegn inni en streng dobles: 'It''s right'.

Mønster-jokere

  • % matcher vilkårlig tekst (inkludert tom).
  • _ matcher nøyaktig ett tegn.
MønsterMatcherMatcher ikke
'Intro%''Intro to SQL''An Intro'
'%Comp%''Intro to Computer Science', 'Computational Bio''Calculus'
'___''CS1''CS101'
'__%'Alt med ≥2 tegn'A'

Escape-tegn

Vil du matche selve % eller _? Bruk ESCAPE:

SELECT *
FROM products
WHERE code LIKE 'ab\%cd%' ESCAPE '\';
-- Matcher alle koder som starter med "ab%cd"
Case-sensitivitet

Standard SQL er case-sensitiv for likhet. 'comp. sci.' = 'Comp. Sci.' evaluerer til false. MySQL og SQL Server er ofte case-insensitiv som default — enda en grunn til å lese DBMS-dokumentasjonen.

05 · ORDER BY · DISTINCT

Sortering, dedup og top-N

Sortering

SELECT *
FROM instructor
ORDER BY salary DESC, name ASC;

Default er stigende (ASC). Du kan sortere på flere kolonner — første sorteringsnøkkel har høyest prioritet, så bruker SQL den neste til å bryte uavgjorte verdier.

DISTINCT — fjerne duplikater

SQL er multiset som default: spørringer beholder duplikater. Be eksplisitt om mengde-semantikk:

Bag (default)
SELECT dept_name
FROM instructor;
Set
SELECT DISTINCT dept_name
FROM instructor;
Hvorfor multiset?

Å fjerne duplikater krever en sortering eller hash-tabell — kostbart. Standarden lar deg velge når kostnaden er verdt det.

Top-N: LIMIT / FETCH FIRST

SELECT name, salary
FROM instructor
ORDER BY salary DESC
LIMIT 5;
-- I standard SQL: FETCH FIRST 5 ROWS ONLY
Sjekkpunkt · Lett
En tabell person(name) har 4 rader: Anne, Bjørn, Anne, Cato. Hvor mange rader returnerer SELECT DISTINCT name FROM person ORDER BY name;?
DISTINCT fjerner duplikatet av Anne. Resultat: Anne, Bjørn, Cato.
06 · Aggregat og GROUP BY

Fra rader til oppsummeringer

Aggregatfunksjoner reduserer en kolonne med mange rader til én verdi. Standarden definerer fem stykker — alle ignorerer NULL bortsett fra COUNT(*).

FunksjonBeskrivelseNULL?
COUNT(*)Antall raderTeller alle rader
COUNT(col)Antall ikke-NULL verdierHopper over NULL
COUNT(DISTINCT col)Antall distinkte ikke-NULL verdierHopper over NULL
SUM(col)Sum (numerisk)Hopper over NULL
AVG(col)GjennomsnittHopper over NULL
MIN(col) / MAX(col)Minste/størsteHopper over NULL

GROUP BY: ett aggregat per gruppe

GROUP BY deler tabellen i grupper basert på like verdier i én eller flere kolonner. Hver gruppe gir én rad i resultatet.

SQL
SELECT dept_name,
       COUNT(*) AS n_ansatte,
       AVG(salary) AS snittlonn
FROM instructor
GROUP BY dept_name;
Resultat
dept_namen_ansattesnittlonn
Comp. Sci.377 333.33
Physics291 000.00
Finance285 000.00
Regel om SELECT-listen

Hver kolonne i SELECT må enten være i GROUP BY, eller pakkes i en aggregatfunksjon. Ellers er resultatet udefinert: hvilken «name» skal man velge når raden representerer 12 ulike ansatte?

HAVING — filter etter aggregering

WHERE filtrerer rader før gruppering. HAVING filtrerer grupper etter aggregering.

RAW namedept ACS BCS CCS DEE EEE FPHY GPHY HBIO WHERE dept <> 'BIO' EFTER WHERE namedept ACS BCS CCS DEE EEE FPHY GPHY GROUP BY dept · COUNT(*) PER GRUPPE deptcnt CS3 EE2 PHY2 HAVING cnt >= 3 SLUTT deptcnt CS3
Pipeline-en: råtabell → WHERE filtrer rader → GROUP BY bunter → HAVING filtrerer grupper. Klikk gjennom stegene under.
Steg 1 / 4
SELECT dept_name, COUNT(*) AS cnt
FROM instructor
WHERE dept_name <> 'BIO'
GROUP BY dept_name
HAVING COUNT(*) >= 3;
Sjekkpunkt · Vanskelig
Tabellen p(grade) har {5, 4, NULL, 3, NULL, 4}. Hva returnerer SELECT COUNT(*), COUNT(grade), AVG(grade) FROM p;?
COUNT(*) ser alle 6 radene. COUNT(grade) hopper over de 2 NULL-ene → 4. AVG ignorerer også NULL: (5+4+3+4)/4 = 4.
07 · Mengdeoperatorer

UNION · INTERSECT · EXCEPT

Kombiner to spørringer som om de var sett. Krav: begge spørringene må ha samme antall kolonner og kompatible typer.

A UNION B
begge sett, dedup
A INTERSECT B
overlapp
A EXCEPT B
i A men ikke i B

Eksempel: emner som ble undervist i begge semestrene

(SELECT course_id FROM section
 WHERE semester = 'Fall'   AND year = 2017)
INTERSECT
(SELECT course_id FROM section
 WHERE semester = 'Spring' AND year = 2018);
UNION vs UNION ALL

UNION fjerner duplikater (set-semantikk). UNION ALL beholder dem (multiset-semantikk). Hvis du vet at kildene ikke har duplikater, er UNION ALL raskere — den slipper sortering.

Sjekkpunkt · Middels
A = {1, 2, 2, 3} og B = {2, 3, 4} (begge multiset). Hva returnerer A UNION ALL B?
UNION ALL slår sammen alle rader — duplikater og alt. UNION (uten ALL) ville gitt {1, 2, 3, 4}.
08 · INSERT · UPDATE · DELETE

Endre data

INSERT

-- Eksplisitt verdier
INSERT INTO instructor (ID, name, dept_name, salary)
VALUES ('77777', 'Lovelace', 'CS', 85000);

-- Sett inn fra spørring
INSERT INTO hi_paid (ID, name)
SELECT ID, name
FROM instructor
WHERE salary > 100000;

UPDATE

UPDATE instructor
SET salary = salary * 1.05
WHERE dept_name = 'CS';
Glem aldri WHERE

UPDATE instructor SET salary = 0; oppdaterer alle radene. Dette er den klassiske produksjons-katastrofen som kan stoppes ved å alltid teste UPDATE-er først som en SELECT med samme WHERE.

DELETE

DELETE FROM instructor
WHERE dept_name = 'BIO'
  AND salary < 50000;

CASE-uttrykk i SET

UPDATE instructor
SET salary =
  CASE
    WHEN salary < 60000 THEN salary * 1.10
    ELSE                       salary * 1.03
  END;

CASE er det nærmeste SQL kommer en if/else, og fungerer både i SELECT, WHERE og SET.

Oppsummering

Det du skal kunne

  1. Skrive CREATE TABLE med riktige typer, primær- og fremmednøkler, og forklare hvorfor hver constraint er der.
  2. Lese en SELECT-spørring og gjenkjenne den logiske evalueringsrekkefølgen (FROM → WHERE → GROUP → HAVING → SELECT → ORDER → LIMIT).
  3. Forklare tre-verdi-logikken og hvorfor = NULL aldri matcher.
  4. Skille mellom WHERE (filtrer rader) og HAVING (filtrer grupper).
  5. Bruke UNION, INTERSECT og EXCEPT samt deres ALL-varianter.
  6. Vite at SELECT-listen ved GROUP BY enten må være i GROUP-listen eller pakket i et aggregat.

Klar for joins og subqueries? Gå til 3B → Joins og subqueries.