Wat is SQL?
SQL staat voor Structured Query Language — uitgesproken als "es-queue-el" of "sequel". Het is een programmeertaal die speciaal ontworpen is om te communiceren met relationele databases. Met SQL kun je data opvragen, invoegen, bijwerken en verwijderen.
SQL bestaat al sinds de jaren zeventig en is tot op de dag van vandaag de standaardtaal voor databases. Vrijwel elke database kent SQL: MySQL, PostgreSQL, Microsoft SQL Server, Oracle, SQLite, maar ook moderne cloud-databases als Snowflake, Google BigQuery, Azure Synapse en Databricks SQL — allemaal gebruiken ze SQL als primaire querytaal.
Dit is waarom SQL zo waardevol is: het is één taal die je overal kunt toepassen. Een SQL-query die je schrijft voor PostgreSQL werkt met kleine aanpassingen ook in Snowflake of SQL Server. De fundamentele syntaxis is gestandaardiseerd (ANSI SQL), ook al heeft elke database zijn eigen uitbreidingen.
SQL is ook een van de eenvoudigste programmeertalen om te leren. De syntax is bijna Engels: SELECT naam FROM klanten WHERE stad = 'Amsterdam' is letterlijk vertaald: "geef mij de naam uit de tabel klanten waar de stad Amsterdam is". Je hoeft geen programmeur te zijn om SQL te leren — het is toegankelijk voor analisten, managers en iedereen die regelmatig met data werkt.
Databases en tabellen
Voordat we SQL-commando's bekijken, is het belangrijk te begrijpen hoe data is georganiseerd. Een relationele database bestaat uit tabellen. Elke tabel is als een spreadsheet met rijen en kolommen.
Stel, je hebt een webshop. Je database bevat dan meerdere tabellen:
- klanten — met kolommen als klant_id, naam, email, stad
- producten — met kolommen als product_id, naam, prijs, categorie, voorraad
- bestellingen — met kolommen als bestelling_id, klant_id, datum, status, totaal
- bestelregels — met kolommen als regel_id, bestelling_id, product_id, aantal, prijs
Elke tabel heeft een primaire sleutel (primary key): een unieke identifier per rij, zoals klant_id. Tabellen zijn aan elkaar gekoppeld via vreemde sleutels (foreign keys): bestelling.klant_id verwijst naar klanten.klant_id.
We gebruiken deze webshop-database door het hele artikel als voorbeeld. Laten we beginnen met de meest gebruikte SQL-operatie: data opvragen met SELECT.
SELECT: data opvragen
SELECT is het meest gebruikte SQL-commando. Het haalt data op uit één of meer tabellen.
-- Alle kolommen uit de tabel klanten opvragen
SELECT * FROM klanten;
-- Specifieke kolommen opvragen
SELECT naam, email, stad FROM klanten;
-- Kolommen hernoemen met een alias
SELECT
naam AS klantnaam,
email AS e_mailadres,
stad
FROM klanten;
Het sterretje (*) selecteert alle kolommen. In de praktijk is het beter om specifieke kolommen te noemen: het is duidelijker voor lezers van je query en sneller voor de database (die alleen de gevraagde kolommen hoeft te lezen).
Je kunt ook berekeningen uitvoeren in een SELECT:
-- Bereken winstmarge
SELECT
naam,
prijs,
inkoopprijs,
prijs - inkoopprijs AS marge,
ROUND((prijs - inkoopprijs) / prijs * 100, 2) AS marge_pct
FROM producten;
Veelgebruikte functies in SELECT:
UPPER(naam)/LOWER(naam)— tekst naar hoofdletters / kleine lettersLENGTH(email)— lengte van een tekststringROUND(prijs, 2)— afronden op decimalenCOALESCE(telefoon, 'onbekend')— vervang NULL door een standaardwaardeCAST(prijs AS VARCHAR)/prijs::VARCHAR— datatype conversie
WHERE: filteren
De WHERE-clausule filtert rijen op basis van een of meer condities. Alleen rijen die aan de conditie voldoen worden geretourneerd.
-- Klanten uit Amsterdam
SELECT naam, email FROM klanten WHERE stad = 'Amsterdam';
-- Producten duurder dan 50 euro
SELECT naam, prijs FROM producten WHERE prijs > 50;
-- Meerdere condities met AND
SELECT naam, prijs FROM producten
WHERE prijs > 50 AND categorie = 'Elektronica';
-- Meerdere condities met OR
SELECT naam, stad FROM klanten
WHERE stad = 'Amsterdam' OR stad = 'Rotterdam';
-- IN-operator: meerdere waarden
SELECT naam, stad FROM klanten
WHERE stad IN ('Amsterdam', 'Rotterdam', 'Utrecht', 'Den Haag');
-- BETWEEN: bereik
SELECT naam, prijs FROM producten
WHERE prijs BETWEEN 25 AND 100;
-- LIKE: patroonherkenning
SELECT naam, email FROM klanten
WHERE email LIKE '%@gmail.com'; -- alle Gmail-adressen
-- IS NULL: lege waarden
SELECT naam FROM klanten WHERE telefoon IS NULL;
-- NOT: negeren
SELECT naam FROM klanten WHERE stad NOT IN ('Amsterdam', 'Rotterdam');
In de LIKE-operator staat het %-teken voor "een willekeurige reeks tekens". _ staat voor precies één willekeurig teken. Zo zoekt 'A%' alles dat begint met A, en '%land%' alles dat het woord "land" bevat.
ORDER BY en LIMIT
ORDER BY sorteert de resultaten. LIMIT (of TOP in SQL Server) beperkt het aantal teruggegeven rijen.
-- Sorteer op prijs, van laag naar hoog (standaard: ASC)
SELECT naam, prijs FROM producten ORDER BY prijs ASC;
-- Sorteer op prijs, van hoog naar laag
SELECT naam, prijs FROM producten ORDER BY prijs DESC;
-- Top 10 duurste producten
SELECT naam, prijs FROM producten
ORDER BY prijs DESC
LIMIT 10;
-- Sorteer op meerdere kolommen
SELECT naam, stad, email FROM klanten
ORDER BY stad ASC, naam ASC;
INSERT: data invoegen
Met INSERT INTO voeg je nieuwe rijen toe aan een tabel.
-- Eén rij invoegen
INSERT INTO klanten (naam, email, stad)
VALUES ('Sophie de Wit', 'sophie@example.com', 'Amsterdam');
-- Meerdere rijen tegelijk invoegen
INSERT INTO producten (naam, prijs, categorie, voorraad)
VALUES
('Laptop Pro 15', 1299.99, 'Elektronica', 25),
('Draadloze muis', 29.95, 'Elektronica', 150),
('Bureau stoel', 349.00, 'Meubels', 40);
-- Invoegen op basis van een andere tabel
INSERT INTO archief_klanten (naam, email, stad, archiveer_datum)
SELECT naam, email, stad, CURRENT_DATE
FROM klanten
WHERE laatste_aankoop < '2022-01-01';
UPDATE: data bijwerken
Met UPDATE wijzig je bestaande rijen in een tabel.
-- Prijs van één product bijwerken
UPDATE producten
SET prijs = 1249.99
WHERE product_id = 42;
-- Meerdere kolommen tegelijk bijwerken
UPDATE klanten
SET
stad = 'Rotterdam',
email = 'nieuw@example.com'
WHERE klant_id = 7;
-- Bijwerken op basis van een berekening
UPDATE producten
SET prijs = prijs * 1.05 -- 5% prijsverhoging
WHERE categorie = 'Elektronica';
Let op: vergeet de WHERE-clausule nooit bij een UPDATE! UPDATE producten SET prijs = 0 zonder WHERE-clausule zet de prijs van alle producten op nul. Voer altijd eerst een SELECT met dezelfde WHERE-conditie uit om te controleren welke rijen je gaat bijwerken.
DELETE: data verwijderen
Met DELETE FROM verwijder je rijen uit een tabel.
-- Eén klant verwijderen
DELETE FROM klanten WHERE klant_id = 99;
-- Alle producten zonder voorraad verwijderen
DELETE FROM producten WHERE voorraad = 0;
-- Alle rijen in een tabel verwijderen (maar de tabelstructuur bewaren)
DELETE FROM tijdelijke_log;
-- Of sneller (maar minder transactie-veilig):
TRUNCATE TABLE tijdelijke_log;
Let op: ook hier geldt: vergeet de WHERE-clausule nooit. DELETE FROM klanten zonder WHERE verwijdert alle klanten permanent. In productie-omgevingen werkt men vaak met soft deletes: een kolom is_verwijderd BOOLEAN die op TRUE wordt gezet in plaats van de rij daadwerkelijk te verwijderen.
JOINs: tabellen combineren
JOINs zijn een van de meest krachtige functies van SQL. Ze combineren data uit meerdere tabellen op basis van een gemeenschappelijke kolom.
INNER JOIN
Een INNER JOIN retourneert alleen rijen die in beide tabellen voorkomen (op basis van de JOIN-conditie).
-- Bestellingen met klantgegevens
SELECT
b.bestelling_id,
k.naam AS klantnaam,
k.stad,
b.datum,
b.totaal
FROM bestellingen b
INNER JOIN klanten k ON k.klant_id = b.klant_id;
-- Bestelling-regels met productnamen
SELECT
br.bestelling_id,
p.naam AS product,
br.aantal,
br.prijs,
br.aantal * br.prijs AS subtotaal
FROM bestelregels br
INNER JOIN producten p ON p.product_id = br.product_id;
LEFT JOIN
Een LEFT JOIN retourneert alle rijen uit de linker tabel, aangevuld met overeenkomende rijen uit de rechter tabel. Als er geen overeenkomst is in de rechter tabel, worden de kolommen gevuld met NULL.
-- Alle klanten, inclusief klanten zonder bestellingen
SELECT
k.naam,
k.email,
COUNT(b.bestelling_id) AS aantal_bestellingen
FROM klanten k
LEFT JOIN bestellingen b ON b.klant_id = k.klant_id
GROUP BY k.klant_id, k.naam, k.email;
-- Klanten die NOOIT besteld hebben
SELECT k.naam, k.email
FROM klanten k
LEFT JOIN bestellingen b ON b.klant_id = k.klant_id
WHERE b.bestelling_id IS NULL;
Overzicht JOIN-typen
| JOIN type | Retourneert | Gebruik |
|---|---|---|
INNER JOIN |
Alleen overeenkomende rijen in beide tabellen | Meest gebruikt; standaard JOIN |
LEFT JOIN |
Alle rijen uit linker tabel + overeenkomsten rechts | "Toon alles uit A, ook als er niets in B is" |
RIGHT JOIN |
Alle rijen uit rechter tabel + overeenkomsten links | Zelden gebruikt; herschirijf als LEFT JOIN |
FULL OUTER JOIN |
Alle rijen uit beide tabellen | Vergelijken van twee datasets |
CROSS JOIN |
Cartesisch product (elke rij × elke rij) | Combinaties genereren; zelden nodig |
Aggregaties: GROUP BY en functies
Aggregatiefuncties berekenen een waarde over meerdere rijen: totaal, gemiddelde, minimum, maximum, telling. In combinatie met GROUP BY bereken je aggregaten per groep.
-- Totale omzet
SELECT SUM(totaal) AS totale_omzet FROM bestellingen;
-- Gemiddelde bestelwaarde
SELECT ROUND(AVG(totaal), 2) AS gem_bestelling FROM bestellingen;
-- Omzet per stad
SELECT
k.stad,
COUNT(b.bestelling_id) AS aantal_bestellingen,
SUM(b.totaal) AS totale_omzet,
ROUND(AVG(b.totaal), 2) AS gem_bestelling
FROM bestellingen b
JOIN klanten k ON k.klant_id = b.klant_id
GROUP BY k.stad
ORDER BY totale_omzet DESC;
-- HAVING: filter op geaggregeerde waarden
-- (WHERE filtert voor aggregatie, HAVING filtert erna)
SELECT
k.stad,
SUM(b.totaal) AS totale_omzet
FROM bestellingen b
JOIN klanten k ON k.klant_id = b.klant_id
GROUP BY k.stad
HAVING SUM(b.totaal) > 10000 -- alleen steden met meer dan €10.000 omzet
ORDER BY totale_omzet DESC;
De meest gebruikte aggregatiefuncties:
COUNT(*)— aantal rijenCOUNT(kolom)— aantal niet-NULL waarden in een kolomCOUNT(DISTINCT kolom)— aantal unieke waardenSUM(kolom)— somAVG(kolom)— gemiddeldeMIN(kolom)/MAX(kolom)— minimum / maximumSTRING_AGG(kolom, ', ')— samenvoeging van tekstwaarden (PostgreSQL/Snowflake)
Subqueries en CTEs
Subqueries zijn queries binnen een query. Ze kunnen voorkomen in SELECT, FROM of WHERE.
-- Klanten die meer dan het gemiddelde hebben besteld
SELECT naam, email
FROM klanten
WHERE klant_id IN (
SELECT klant_id
FROM bestellingen
GROUP BY klant_id
HAVING SUM(totaal) > (SELECT AVG(totaal) FROM bestellingen)
);
CTEs (Common Table Expressions) zijn subqueries die een naam krijgen via WITH. Ze maken complexe queries veel leesbaarder en zijn herbruikbaar binnen dezelfde query.
WITH
omzet_per_klant AS (
SELECT
klant_id,
COUNT(*) AS aantal_bestellingen,
SUM(totaal) AS totale_omzet
FROM bestellingen
GROUP BY klant_id
),
klant_segmenten AS (
SELECT
klant_id,
totale_omzet,
CASE
WHEN totale_omzet >= 1000 THEN 'Platinum'
WHEN totale_omzet >= 500 THEN 'Gold'
WHEN totale_omzet >= 100 THEN 'Silver'
ELSE 'Bronze'
END AS segment
FROM omzet_per_klant
)
SELECT
k.naam,
ks.totale_omzet,
ks.segment
FROM klanten k
JOIN klant_segmenten ks ON ks.klant_id = k.klant_id
ORDER BY ks.totale_omzet DESC;
CTEs zijn in de meeste gevallen te prefereren boven geneste subqueries: ze zijn makkelijker te lezen, te debuggen en stap voor stap te begrijpen.
Wanneer gebruik je SQL?
SQL is de go-to taal voor een brede reeks taken:
- Data analyse: vragen beantwoorden op basis van data in een database. Hoeveel klanten zijn er per regio? Welke producten verkopen het best? Wat is de gemiddelde orderwaarde per maand?
- Rapportage: data klaarmaken voor dashboards in Power BI, Tableau of Looker. Meeste BI-tools draaien SQL onder de motorkap.
- Data transformaties: in data engineering gebruik je SQL (via dbt of direct in een DWH) om ruwe data te transformeren naar analytische modellen.
- Applicatieontwikkeling: webapplicaties communiceren via SQL met hun databases. Een webshop slaat bestellingen op in een database en haalt productinformatie op met SQL.
- Data quality checks: SQL-queries om datakwaliteit te controleren: zijn er duplicaten, NULL-waarden in verplichte velden, waarden buiten verwachte ranges?
SQL is niet de beste keuze voor: complexe machine learning-algoritmen (Python/R), het bouwen van user interfaces (HTML/CSS/JavaScript), of systeemprogrammering (C/Go/Rust). SQL is een query-taal, geen algemene programmeertaal.
Hoe leer je SQL?
SQL leer je het snelst door te doen. Enkele aanbevolen middelen en aanpak:
- Installeer een gratis database: PostgreSQL is de beste keuze voor beginners — het is volledig gratis, krachtig en breed ingezet. Installeer DBeaver als gratis SQL-client.
- Oefen met een dataset: gebruik een van de vele gratis datasets op Kaggle (NYC taxi trips, Northwind database, chinook). Maak je eigen tabellen en oefendata aan.
- Online oefenplatforms: SQLZoo en Mode Analytics bieden interactieve SQL-oefeningen in de browser — geen installatie nodig.
- Bouw een project: kies een onderwerp dat je interesseert (voetbalstatistieken, crypto-koersen, boekrecensies) en analyseer echte data met SQL. Leren door een echte vraag te beantwoorden gaat sneller dan losstaande oefeningen.
- Lees het execution plan: zodra je basisqueries begrijpt, is het leren lezen van execution plans de volgende grote stap. Dit verdiept je begrip van hoe de database werkt.
Met 10-15 uur studie beheers je de basis van SQL. Met 50-100 uur oefen-ervaring schrijf je comfortabel complexe queries. Echt meester worden in SQL — met window functions, query-optimalisatie en geavanceerde patronen — vergt maanden tot jaren van praktijkervaring.
Conclusie
SQL is de meest toegankelijke en nuttige technische vaardigheid die je kunt leren als je met data werkt. De basis is snel te leren en direct toepasbaar. Of je nu data analyst bent die inzichten wil halen uit een database, een developer die een applicatie bouwt, of een data engineer die pipelines bouwt — SQL is altijd relevant.
De kern van SQL is eenvoudig: SELECT om data op te vragen, WHERE om te filteren, JOIN om tabellen te combineren, en GROUP BY met aggregatiefuncties om samen te vatten. Met deze bouwstenen kun je vrijwel elke data-vraag beantwoorden.
Begin vandaag: installeer PostgreSQL, laad een dataset en begin met schrijven. Na je eerste werkende complexe query met JOINs en aggregaties begrijp je waarom SQL al vijftig jaar de ruggengraat van de datawereld is.
SQL en data engineering voor jouw organisatie?
DataPartner365 helpt Nederlandse organisaties bij het opzetten van data platforms, SQL-optimalisatie en data engineering.