SQL-spiekbriefje

Alles uit de cursus op één pagina: van je eerste SELECT tot JOINs, window functions en het aanpassen van data. Elke voorbeeldquery werkt op de videotheek-dataset uit de lessen (films, leden en uitleningen).

Tip: druk deze pagina af of bewaar ze als pdf.

Gegevens opvragen

SELECT * FROM films
Alle kolommen en alle rijen van een tabel.
SELECT titel, jaar FROM films
Alleen de kolommen die je noemt, in die volgorde.
SELECT titel AS film FROM films
AS geeft een kolom een andere naam in het resultaat.
SELECT titel, prijs_per_dag * 2 AS weekend FROM films
Rekenen met +, -, * en /, per rij.
SELECT titel FROM films LIMIT 5
Hoogstens 5 rijen. Zonder ORDER BY kiest de database welke.
SELECT titel FROM films LIMIT 5 OFFSET 10
OFFSET slaat eerst rijen over: handig om per pagina te tonen.

Filteren met WHERE

SELECT titel FROM films WHERE genre = 'horror'
Tekst tussen enkele aanhalingstekens. = let op hoofdletters.
SELECT titel FROM films WHERE duur_min >= 120
=, <> (of !=), <, <=, >, >=. Getallen zonder aanhalingstekens.
SELECT * FROM uitleningen WHERE uitgeleend_op > '2024-10-15'
Datums als tekst 'jaar-maand-dag', altijd tussen aanhalingstekens.
SELECT titel FROM films WHERE (genre = 'drama' OR genre = 'komedie') AND jaar > 2000
AND gaat voor OR: zet haakjes om wat bij elkaar hoort.
SELECT titel FROM films WHERE NOT genre = 'animatie'
NOT draait een voorwaarde om.

Lijsten, bereiken en patronen

SELECT naam FROM leden WHERE gemeente IN ('Leuven', 'Gent')
IN is een korte OR. NOT IN is het omgekeerde.
SELECT titel FROM films WHERE jaar BETWEEN 1990 AND 1999
BETWEEN neemt beide grenzen mee. Kleinste waarde eerst.
SELECT titel FROM films WHERE titel LIKE 'The %'
% is nul of meer tekens, _ precies één. In SQLite negeert LIKE hoofdletters.
SELECT naam FROM leden WHERE email IS NULL
Ontbrekende waarden zoek je met IS NULL of IS NOT NULL, nooit met = NULL.

Sorteren en dubbels

SELECT titel, score FROM films ORDER BY score DESC
ORDER BY sorteert, ASC oplopend (standaard), DESC aflopend.
SELECT titel, jaar FROM films ORDER BY jaar DESC LIMIT 3
Sorteren en dan beperken geeft "de nieuwste drie".
SELECT genre, titel, score FROM films ORDER BY genre, score DESC
De tweede kolom beslist bij gelijke waarden in de eerste. Elke kolom heeft haar eigen richting. NULL staat bij oplopend sorteren vooraan.
SELECT DISTINCT genre FROM films
DISTINCT haalt dubbele rijen weg. Bij meerdere kolommen telt de combinatie.

Tellen en rekenen

SELECT COUNT(*) FROM films
COUNT(*) telt rijen. Je krijgt één rij met één getal.
SELECT COUNT(score), COUNT(DISTINCT genre) FROM films
COUNT(kolom) slaat NULL over, COUNT(DISTINCT kolom) telt verschillende waarden.
SELECT SUM(boete), AVG(boete) FROM uitleningen
SUM telt op, AVG middelt. Beide slaan NULL over. Zonder rijen geeft SUM NULL, geen 0.
SELECT MIN(jaar), MAX(jaar) FROM films
Kleinste en grootste waarde. Werkt ook op tekst en datums.
SELECT ROUND(AVG(score), 1) FROM films
ROUND(getal, decimalen) rondt af. Let op: 7 / 2 geeft in SQLite 3, schrijf 7 * 1.0 / 2 voor 3.5.

Groeperen

SELECT genre, COUNT(*) AS aantal FROM films GROUP BY genre
Eén rij per groep. Elke kolom in SELECT staat in GROUP BY of in een functie als COUNT.
SELECT genre, COUNT(*) FROM films GROUP BY genre HAVING COUNT(*) >= 4
WHERE filtert rijen vóór het groeperen, HAVING filtert groepen erna.
SELECT genre, AVG(score) AS gemiddeld FROM films WHERE jaar > 1990 GROUP BY genre ORDER BY gemiddeld DESC
Sorteren mag op het resultaat van een functie, of op zijn alias.
SELECT gemeente, abonnement, COUNT(*) FROM leden GROUP BY gemeente, abonnement
Met meerdere kolommen is elke combinatie een groep.

Tabellen combineren

De tabel vóór JOIN is links, de tabel erna rechts. Het gekleurde deel blijft over.

SELECT f.titel, u.uitgeleend_op FROM uitleningen u JOIN films f ON u.film_id = f.id
JOIN (of INNER JOIN): alleen rijen met een partner aan beide kanten. u en f zijn aliassen.
SELECT f.titel, u.id FROM films f LEFT JOIN uitleningen u ON u.film_id = f.id
LEFT JOIN: elke rij van links, ook zonder partner. Rechts staat dan NULL.
SELECT f.titel, u.id FROM uitleningen u RIGHT JOIN films f ON u.film_id = f.id
RIGHT JOIN: elke rij van rechts. Hetzelfde als een LEFT JOIN met de tabellen omgewisseld.
SELECT l.naam, u.id FROM leden l FULL JOIN uitleningen u ON u.lid_id = l.id
FULL JOIN: alle rijen van beide kanten, met NULL waar een partner ontbreekt.
SELECT f.titel FROM films f LEFT JOIN uitleningen u ON u.film_id = f.id WHERE u.id IS NULL
Wat ontbreekt: LEFT JOIN en dan IS NULL op de rechterkant. Hier: films die nooit verhuurd werden.
SELECT l.naam, f.titel FROM uitleningen u JOIN leden l ON u.lid_id = l.id JOIN films f ON u.film_id = f.id
Meerdere JOIN's achter elkaar, elk met een eigen ON.
SELECT a.naam, b.naam FROM leden a JOIN leden b ON a.gemeente = b.gemeente AND a.id < b.id
Self join: dezelfde tabel twee keer, met twee aliassen. Hier: leden uit dezelfde gemeente.

Slimmer queryen

SELECT titel, CASE WHEN score >= 8 THEN 'topper' WHEN score >= 7 THEN 'goed' ELSE 'matig' END AS oordeel FROM films
CASE kiest per rij een waarde, zoals een als-dan. ELSE vangt de rest op, ook NULL.
SELECT titel FROM films WHERE score > (SELECT AVG(score) FROM films)
Een subquery tussen haakjes geeft één waarde om mee te vergelijken.
SELECT naam FROM leden WHERE id IN (SELECT lid_id FROM uitleningen WHERE boete > 0)
Een subquery met IN geeft een lijst. Hier de leden die ooit een boete kregen.
WITH populair AS (SELECT film_id, COUNT(*) AS keer FROM uitleningen GROUP BY film_id) SELECT f.titel, p.keer FROM populair p JOIN films f ON p.film_id = f.id
WITH (een CTE) geeft een tussenresultaat een naam, zodat je query leesbaar blijft.
SELECT naam FROM leden WHERE gemeente = 'Gent' UNION SELECT naam FROM leden WHERE abonnement = 'premium'
UNION zet resultaten onder elkaar en haalt dubbels weg. UNION ALL houdt ze.

Tekst, datums en NULL

SELECT UPPER(titel), LOWER(genre), LENGTH(titel) FROM films
Hoofdletters, kleine letters en het aantal tekens.
SELECT naam || ' (' || gemeente || ')' AS lid FROM leden
|| plakt tekst aan elkaar.
SELECT SUBSTR(titel, 1, 3), REPLACE(titel, ' ', '_'), TRIM('  ja  ') FROM films
Een stuk tekst nemen, iets vervangen en spaties aan de randen weghalen.
SELECT titel FROM films WHERE LOWER(genre) = 'horror'
Zonder last van hoofdletters vergelijken.
SELECT uitgeleend_op, strftime('%Y', uitgeleend_op) AS jaar, date(uitgeleend_op, '+7 days') AS terug FROM uitleningen
strftime haalt een deel uit een datum, date(..., '+7 days') rekent ermee. date('now') is vandaag.
SELECT julianday(teruggebracht_op) - julianday(uitgeleend_op) AS dagen FROM uitleningen
Het verschil tussen twee datums, in dagen.
SELECT naam, COALESCE(email, 'geen e-mail') FROM leden
COALESCE geeft de eerste waarde die geen NULL is: handig als reservewaarde.

Window functions

Rekenen over meerdere rijen, zonder ze samen te voegen tot één rij zoals GROUP BY doet.

SELECT titel, score, ROW_NUMBER() OVER (ORDER BY score DESC) AS plaats FROM films
ROW_NUMBER() nummert de rijen in de volgorde van OVER (ORDER BY ...).
SELECT titel, genre, score, RANK() OVER (PARTITION BY genre ORDER BY score DESC) AS plaats FROM films
PARTITION BY begint per genre opnieuw. RANK() geeft gelijke scores dezelfde plaats.
SELECT uitgeleend_op, boete, SUM(boete) OVER (ORDER BY uitgeleend_op) AS totaal FROM uitleningen
Een lopend totaal, rij per rij opgeteld.

Data aanpassen

In Lurndo oefen je zonder risico. Na elke query zet de database zich terug.

INSERT INTO leden (naam, gemeente, geboortejaar, lid_sinds, abonnement) VALUES ('Ann Peeters', 'Lier', 1985, '2025-10-01', 'basis')
Een nieuwe rij. Kolommen die je niet noemt, worden NULL (of hun standaardwaarde).
UPDATE films SET prijs_per_dag = prijs_per_dag + 0.5 WHERE jaar >= 2020
Bestaande rijen aanpassen. Zonder `WHERE` verander je elke rij.
DELETE FROM uitleningen WHERE teruggebracht_op IS NOT NULL AND boete = 0
Rijen verwijderen. Zonder `WHERE` is de hele tabel leeg.
BEGIN; UPDATE leden SET abonnement = 'premium' WHERE id = 1; COMMIT;
Een transactie: alles of niets. COMMIT bewaart, ROLLBACK maakt alles ongedaan.

Tabellen maken

CREATE TABLE reserveringen (id INTEGER PRIMARY KEY, film_id INTEGER NOT NULL REFERENCES films (id), naam TEXT NOT NULL, datum TEXT DEFAULT (date('now')))
Typen in SQLite: INTEGER, REAL, TEXT, BLOB. PRIMARY KEY, NOT NULL, DEFAULT en REFERENCES (vreemde sleutel) bewaken je data.
ALTER TABLE leden ADD COLUMN telefoon TEXT
Een kolom toevoegen aan een bestaande tabel.
DROP TABLE uitleningen
Een tabel met al haar rijen verwijderen. Dat is definitief.
CREATE INDEX idx_films_genre ON films (genre)
Een index maakt zoeken op die kolom sneller, ten koste van wat opslag.
CREATE VIEW recente_films AS SELECT titel, jaar FROM films WHERE jaar >= 2020; SELECT * FROM recente_films
Een view is een opgeslagen query die je gebruikt als een tabel.

De volgorde van een query

SELECT genre, COUNT(*) AS aantal FROM films WHERE jaar >= 2000 GROUP BY genre HAVING COUNT(*) > 1 ORDER BY aantal DESC LIMIT 3
Zo schrijf je het: SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. De database werkt in een andere volgorde: eerst FROM en JOIN, dan WHERE, GROUP BY, HAVING, daarna SELECT, en pas op het einde ORDER BY en LIMIT. Daarom mag een alias wel in ORDER BY, maar niet in WHERE.