Tabellen, rijen en sleutels
What you'll learn
- tabellen, rijen en kolommen onderscheiden en uitleggen waarom elke rij een primaire sleutel nodig heeft (meestal
id) - verbindingen tussen tabellen vinden via een vreemde sleutel:
orders.user_id → users.id - een surrogaatsleutel (
IDENTITY, ) onderscheiden van een natuurlijke sleutel (e-mail, ISBN) en uitleggen waarom een primaire sleutel niet mag veranderen - de uniciteit van een veld zoals
emailvastleggen met eenUNIQUE-beperking, zonder er de primaire sleutel van te maken
De inventaris is open. QUERY ontvouwt boven het bureau een hologram: duizenden records hangen in een strak raster in de lucht, en tussen sommige records lopen dunne amberkleurige draden. Je raakt er een aan; hij trilt als een snaar. Dit is geen stapel bestanden. Dit is een weefsel.
Tabellen, rijen, kolommen
Een relationele database lijkt op een nette catalogus: de gegevens zijn verdeeld over tabellen, en binnen elke tabel heb je kolommen (welke eigenschappen we bewaren) en rijen (de concrete records).
Neem de tabel met kopers users: elke rij is één koper van de oude aarde, en de kolommen beschrijven diens id, full_name, email, country, city, signup_date.
Om mensen met dezelfde naam niet te verwarren, heeft elke rij een primaire sleutel (): een unieke identificator, meestal de kolom id. Via die sleutel kunnen andere tabellen naar deze rij verwijzen met een vreemde sleutel (). Zo heeft een bestelling in orders bijvoorbeeld een user_id: daarmee onthoudt de bestelling bij welke koper ze hoort. De amberkleurige draden op het hologram zijn precies die verbindingen via sleutels.
QUERY: Zolang de sleutel heel is, blijft de draad heel. Anderhalve eeuw is voorbij, maar elke bestelling herinnert zich nog steeds haar mens.
Voer de query uit en bekijk hoe de kopers van «Kotomarket» eruitzien: records die niemand meer heeft geopend sinds de tijd van het oude Net.

Tables, rows, columns
A relational database is like a tidy catalog: the data is sorted into tables, and inside each table there are columns (what properties we store) and rows (the individual records).
Take the buyers’ table users: each row is one buyer from old Earth, and the columns describe their id, full_name, email, country, city, signup_date.
So that people with the same name don’t get confused, every row has a — a unique identifier, usually the id column. Through it, other tables can reference this row using a . For example, an order in orders has a user_id — that’s how an order remembers its buyer. Those amber threads on the hologram are exactly these key-based links.
QUERY: As long as the key holds, the thread holds. A century and a half on, every order still remembers its person.
Run the query and see what Kotomarket’s buyers look like — records no one has opened since the days of the old Net:
| id | full_name | city | signup_date |
|---|---|---|---|
| 1 | Артём Волков | Санкт-Петербург | 2024-10-20 |
| 2 | Екатерина Алексеев | Екатеринбург | 2025-01-25 |
| 3 | Николай Никитин | Алматы | 2024-09-21 |
| 4 | Екатерина Иванов | Новосибирск | 2024-05-04 |
| 5 | Елена Петров | Казань | 2025-01-05 |
| 6 | Ирина Кузнецов | Новосибирск | 2024-09-12 |
Een primaire sleutel helpt je foutloos één rij te vinden (meestal id). Een vreemde sleutel verbindt tabellen: zo laat orders.user_id → users.id bijvoorbeeld zien van wie een bestelling is. Verderop ontvouwt QUERY de hele kaart van de momentopname voor je: alle vijf tabellen.
orders.user_id verwijst naar de primaire sleutel users.id: zo onthoudt een bestelling bij welke koper ze hoort.Natuurlijke of surrogaatsleutel
Waar komt een primaire sleutel vandaan? Er zijn twee routes. Een natuurlijke sleutel is een echt attribuut dat toch al uniek is: het e-mailadres van een koper, de ISBN van een boek, een valutacode. Een surrogaatsleutel is een kunstmatige identificator zonder betekenis buiten de database: een autonummering of een . In «Kotomarket» worden overal surrogaat-id's gebruikt, en dat is een standaardoplossing:
-- Surrogaatsleutel: de database geeft zelf het volgende nummer uit (PostgreSQL)
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email TEXT NOT NULL UNIQUE, -- de natuurlijke kandidaat leeft ernaast als UNIQUE
full_name TEXT NOT NULL
);
De belangrijkste eigenschap van een primaire sleutel is dat hij niet mag veranderen. Andere tabellen verwijzen ernaar met vreemde sleutels; verander je de waarde, dan moet je alle draden tegelijk bijwerken: in orders, in events, overal. En «eeuwige» natuurlijke attributen bestaan vrijwel niet: mensen veranderen van e-mailadres en achternaam, telefoonnummers worden overgedragen, zelfs ISBN's kunnen opnieuw worden uitgegeven. Een surrogaat-id verandert nooit, juist omdat het niets betekent.
Elke primaire sleutel moet uniek, niet NULL en stabiel zijn. Laat natuurlijke sleutels over aan kleine, onveranderlijke naslagtabellen, bijvoorbeeld de valutacode 'RUB' uit ISO 4217. De uniciteit van een natuurlijke kandidaat zoals email leg je vast met een aparte UNIQUE-beperking, zoals in het voorbeeld hierboven: de verbindingen blijven intact, de data blijft betrouwbaar, en de koper mag nog steeds zijn e-mailadres wijzigen.
Even vooruitlopend: de syntaxis voor het aanmaken van tabellen en beperkingen (CREATE TABLE, PRIMARY KEY, UNIQUE) behandelen we in Hoofdstuk 9. Kijk hier vooral naar de structuur van de sleutel, niet naar het commando: een surrogaat-id is de primaire sleutel, terwijl email daarnaast als UNIQUE bestaat.
Interview question
Sollicitatievraag: wat is het verschil tussen een surrogaatsleutel en een natuurlijke sleutel, en welke kies je voor een gebruikerstabel?
Sterk antwoord: een natuurlijke sleutel is een echt uniek attribuut (e-mail, ISBN), een surrogaatsleutel is een kunstmatige identificator (een IDENTITY-kolom of een ). Voor gebruikers kies ik een surrogaatsleutel: een primaire sleutel mag niet veranderen, want er verwijzen vreemde sleutels naar, en mensen kunnen hun e-mailadres wijzigen. De uniciteit van het e-mailadres leg je daarnaast vast met een aparte UNIQUE-beperking. Een natuurlijke sleutel is logisch in stabiele naslagtabellen, zoals valutacodes uit ISO 4217.