Tabele, rânduri și chei
What you'll learn
- să deosebești tabelele, rândurile și coloanele și să explici de ce fiecare rând are nevoie de o cheie primară (de obicei
id) - să găsești legăturile dintre tabele după cheia externă:
orders.user_id → users.id - să deosebești o cheie surogat (
IDENTITY, ) de una naturală (email, ISBN) și să argumentezi de ce o cheie primară nu trebuie să se schimbe - să fixezi unicitatea unui câmp precum
emailcu o restricțieUNIQUE, fără să-l transformi în cheie primară
Inventarul e deschis. QUERY desfășoară pe birou o hologramă: mii de înregistrări plutesc în aer într-o rețea ordonată, iar între unele se întind fire subțiri, chihlimbarii. Atingi unul și sună ca o coardă. Nu e un morman de fișiere. E o țesătură.
Tabele, rânduri, coloane
O bază de date relațională seamănă cu un catalog bine îngrijit: datele sunt așezate în tabele, iar fiecare tabel are coloane (ce proprietăți păstrăm) și rânduri (înregistrările concrete).
Ia tabelul cumpărătorilor users: fiecare rând este un cumpărător al vechiului Pământ, iar coloanele descriu id, full_name, email, country, city, signup_date.
Ca să nu încurci oamenii cu nume identice, fiecare rând are o cheie primară () — un identificator unic, de obicei coloana id. Prin ea, alte tabele pot trimite la acest rând cu ajutorul unei chei externe (). De exemplu, în comanda orders există user_id — așa își ține minte comanda cumpărătorul. Firele chihlimbarii de pe hologramă sunt tocmai legăturile prin chei.
QUERY: Cât timp cheia e întreagă, și firul rămâne întreg. A trecut un secol și jumătate, iar fiecare comandă încă își ține minte omul.
Rulează interogarea și vezi cum arată cumpărătorii „Kotomarket” — înregistrări pe care nu le-a mai deschis nimeni din vremea vechii Rețele:

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 |
Cheia primară ajută să găsești fără greș un singur rând (de obicei id). Cheia externă leagă tabelele: de exemplu, orders.user_id → users.id arată a cui este comanda. Mai departe, QUERY va desfășura în fața ta toată harta copiei de arhivă — cele cinci tabele, complet.
orders.user_id face referință la cheia primară users.id — așa își ține minte comanda cumpărătorul.Cheie naturală sau surogat
De unde vine cheia primară? Există două variante. Cheia naturală este un atribut real care este oricum unic: emailul cumpărătorului, ISBN-ul unei cărți, codul monedei. Cheia surogat este un identificator artificial, fără sens în lumea exterioară: o autonumerotare sau un . În „Kotomarket” se folosesc peste tot id-uri surogat — și aceasta este o soluție tipică:
-- Cheie surogat: baza emite singură următorul număr (PostgreSQL)
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email TEXT NOT NULL UNIQUE, -- candidatul natural trăiește alături ca UNIQUE
full_name TEXT NOT NULL
);
De ce așa? Proprietatea esențială a cheii primare este că ea nu trebuie să se schimbe. Cheile externe din alte tabele trimit la PK, iar schimbarea valorii ar cere actualizarea tuturor firelor deodată — în orders, în events, peste tot. În plus, atribute naturale „veșnice” aproape că nu există: oamenii își schimbă emailul și numele, telefoanele se reatribuie, până și ISBN-urile se reeditează. Un id surogat nu se schimbă niciodată tocmai fiindcă nu înseamnă nimic.
Cerințele pentru orice cheie primară: să fie unică, să nu fie NULL, să fie stabilă. Păstrează cheile naturale pentru micile tabele de referință care nu se schimbă — de exemplu, codul monedei 'RUB' din standardul ISO 4217. Iar unicitatea unui candidat natural precum email fixeaz-o cu o restricție UNIQUE separată, ca în exemplul de mai sus: legăturile se păstrează, datele rămân corecte, iar cumpărătorului nu îi interzici să-și schimbe emailul.
Notă pentru mai târziu: sintaxa propriu-zisă pentru crearea tabelelor și a restricțiilor (CREATE TABLE, PRIMARY KEY, UNIQUE) este tema Capitolului 9. Aici uită-te la structura cheii, nu la comandă: la faptul că un id surogat a devenit cheie primară, iar email trăiește alături ca UNIQUE.
Interview question
Întrebare de interviu: prin ce se deosebește o cheie surogat de una naturală și pe care o vei alege pentru un tabel de utilizatori?
Răspuns puternic: cheia naturală este un atribut real, unic (email, ISBN), iar cheia surogat este un identificator artificial (o coloană IDENTITY sau un ). Pentru utilizatori aleg surogat: cheia primară nu trebuie să se schimbe, fiindcă la ea trimit cheile externe, iar oamenii își schimbă emailul. Unicitatea emailului se fixează separat, cu o restricție UNIQUE. O cheie naturală este justificată în tabele de referință stabile, precum codurile valutare ISO 4217.