Databaser uden tåge

Kotomarkets skema

11 min
What you'll learn
  • at finde den rigtige tabel blandt de fem i Kotomarket: users, products, orders, order_items, events
  • at læse et ER-diagram: bestemme en forbindelses kardinalitet (1:N, N:M, 1:1) ud fra, hvor fremmednøglen ligger
  • at folde en »mange-til-mange«-forbindelse ud via en mellemtabel med to FK — som order_items med order_id + product_id
  • at forklare, hvorfor en ordres indhold ikke kan gemmes som en streng af id'er direkte i orders

I dag fører QUERY hele indekset op på hovedbordet på én gang. Fem lysende flader svæver i luften og roterer langsomt — et kort over den verden, der overlevede. Ved siden af blinker konserveringsloggen, der følger med snapshottet, og én linje i den er understreget: »Overdrager fem tabeller og sporet af en sjette. — K.« Du tæller fladerne. Præcis fem. Hvor er sporet?

QUERY: Lad dig ikke distrahere af spor. Lær først disse fem så godt, at du kan finde vej med lukkede øjne — resten viser arkivet selv, når det finder dig klar.

Kotomarkets fem tabeller

Fra nu af arbejder vi med denne database — et af en netbutik fra 2024. Hold den som et kort over butikken: hvem der kom ind, hvad der ligger på butiksdisken, hvad der blev købt, og hvilke handlinger folk udførte før købet.

TabelHvad den rummer
userskunder: id, navn, by og registreringsdato
productsvarer på butiksdisken: id, navn, kategori, pris og lagerbeholdning
ordersordrer: id, user_id, dato, status og beløb
order_itemsordrernes indhold: hvilken vare, hvor mange stk. og til hvilken pris
eventsadfærdshændelser: visninger, tilføjelser til kurv og køb

Forbindelserne læses sådan: én user → mange orders; én order → mange order_items; én product → mange order_items. Hvis du farer vild, så åbn skemaet til højre — det er som butikkens plantegning.

Lad os kigge ind i ordretabellen: hver række har et user_id — en henvisning til en kunde. Sådan knyttes én tabel til en anden, og kortet holder op med at være fem adskilte øer.

Fem holografiske tabel-flader roterer som en stjernekonstellation, forbundet af tråde; ude til siden anes svagt det stiplede omrids af en sjette
Arkivets kort: fem tabeller og forbindelserne imellem dem. Konserveringsloggen lover oven i købet »sporet af en sjette« — men det er endnu ingen steder at se.

Kotomarket’s five tables

From here on we’ll be working with this database — a of an online shop from 2024. Hold it like a map of the store: who walked in, what’s on the shelves, what they bought, and what they did before buying.

TableWhat it holds
usersbuyers: id, name, city, and signup date
productsstorefront items: id, name, category, price, and stock
ordersorders: id, user_id, date, status, and total
order_itemsorder contents: which product, how many, and at what price
eventsbehavioral events: views, add-to-carts, and purchases

The links read like this: one user → many orders; one order → many order_items; one product → many order_items. If you get lost, open the schema on the right — it’s like the floor plan of the shop.

Let’s peek into the orders table: every row has a user_id — a reference to a buyer. That’s how one table links to another, and the map stops being five separate islands.

Ordrer og deres forbindelse til en kunde via user_id:
Query result
iduser_idstatustotal_amount
118paid5980.00
210paid19750.00
326cancelled9560.00
426paid15530.00
58paid26710.00
637paid42110.00

Sådan læser du et ER-diagram

Kortet, QUERY foldede ud, kaldes i branchen et ER-diagram (entity–relationship): rektanglerne er tabeller, linjerne imellem dem er forbindelser via fremmednøgler. Det vigtigste på en linje er kardinaliteten: hvor mange rækker på den ene side, der svarer til hvor mange på den anden.

  • 1:N, en-til-mange — den hyppigste forbindelse. Én kunde — mange ordrer. Fremmednøglen ligger altid på »mange«-siden: user_id gemmes i orders, ikke omvendt. Det er netop læsereglen: fandt du FK'en — fandt du N-siden.
  • N:M, mange-til-mange — i én ordre er der mange varer, og én vare optræder i mange ordrer. Den slags forbindelse kan ikke udtrykkes direkte i en relationel database: der er ingen steder at lægge fremmednøglen. Man folder den ud via en mellemtabel — hos os er det order_items. Hver af dens rækker bærer et par henvisninger order_id + product_id og forvandler én N:M-forbindelse til to 1:N-forbindelser. Bonus: forbindelsen selv får attributter — antallet af stk. og prisen på købstidspunktet.
  • 1:1, en-til-en — forekommer sjældnere: for eksempel flyttes tunge eller private felter ud i en separat tabel med samme nøgle.
-- N:M-opløsningen i praksis: par »ordre — vare« fra order_items
SELECT order_id, product_id, quantity
FROM order_items
LIMIT 6;
usersidnameproductsidpriceordersiduser_ideventsuser_idproduct_idorder_itemsorder_idproduct_iduser_id → idproduct_id → idPKFK (reference)
Kotomarkets ER-diagram: 1:N-forbindelser fra users til orders og N:M-opløsningen mellem orders og products via order_items.

Faldgrube: at gemme en ordres indhold direkte i orders — som strengen '7,12,3' eller et array af identifikatorer. Den slags data kan man ikke beskytte med en fremmednøgle, tælle ærligt eller sammenføje med butiksdisken uden akrobatik. Ser du en »mange-til-mange«-forbindelse — så opret en mellemtabel med to fremmednøgler, som order_items.

Interview question

Spørgsmål fra en jobsamtale: hvordan implementerer man en »mange-til-mange«-forbindelse i en relationel database?

Et stærkt svar: via en mellemtabel med to fremmednøgler til de tabeller, der skal forbindes — som order_items med order_id og product_id: den forvandler N:M til to 1:N-forbindelser. Samtidig gemmer man i den forbindelsens egne attributter — antal, prisen på købstidspunktet. Primærnøglen i sådan en tabel er enten sammensat af de to FK'er eller en surrogat-id.

Check yourself
Hvor i skemaet kan man se, hvilken vare der havnede i hvilken ordre?