SQL și baze de date relaționale
Tabele, chei, CRUD, JOIN, relații și query-uri parametrizate.
Actualizat
Ce este o bază de date relațională
O bază de date relațională (PostgreSQL, MySQL, SQLite) ține datele în tabele: fiecare tabel are coloane cu tipuri fixe, iar fiecare rând e un element. Tabelele se leagă între ele prin chei — de aici „relațional”.
users posts
id | name | email id | user_id | title
---+-------+------------ ---+---------+---------
1 | Ana | ana@x.ro 1 | 1 | Salut
2 | Ion | ion@x.ro 2 | 1 | Next 16
SQL e limbajul cu care întrebi și modifici aceste date. Chiar dacă folosești un ORM, SQL-ul e ce rulează de fapt — merită să-l citești fluent. Aplicația asta folosește PostgreSQL pe Neon.
Cheile
| Cheie | Rol |
|---|---|
| primary key | identifică unic un rând (id) |
| foreign key | coloană care indică spre cheia altui tabel (posts.user_id → users.id) |
| unique | valoare care nu se poate repeta (email) |
| index | structură care face căutările pe o coloană rapide |
Cele 4 operații (CRUD)
SELECT id, title FROM posts WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;
INSERT INTO posts (user_id, title) VALUES (1, 'Salut') RETURNING id;
UPDATE posts SET title = 'Salut!' WHERE id = 1;
DELETE FROM posts WHERE id = 1;UPDATE și DELETE fără WHERE afectează toate rândurile. Primul lucru pe care îl verifici.
SELECT pe bucăți
| Clauză | Rol | Echivalent JS |
|---|---|---|
SELECT col1, col2 |
ce coloane | map |
FROM tabel |
din ce tabel | array-ul |
WHERE cond |
ce rânduri | filter |
ORDER BY col DESC |
ordinea | toSorted |
LIMIT n OFFSET m |
câte, de unde | slice |
GROUP BY col + COUNT(*) |
grupare și agregare | Object.groupBy + length |
JOIN — combini tabele
SELECT posts.title, users.name
FROM posts
JOIN users ON users.id = posts.user_id;| Tip | Păstrează |
|---|---|
JOIN (inner) |
doar rândurile care au pereche în ambele tabele |
LEFT JOIN |
toate rândurile din stânga; dreapta = NULL dacă lipsește perechea |
Relații — tipuri
| Relație | Exemplu | Cum se modelează |
|---|---|---|
| one-to-many | un user → multe postări | posts.user_id |
| many-to-many | postări ↔ taguri | tabel de legătură post_tags (post_id, tag_id) |
| one-to-one | user → profil | profiles.user_id unique |
SQL injection — regula de aur
Niciodată nu lipești input de la user direct în textul SQL:
sql(`SELECT * FROM users WHERE email = '${email}'`) // ✗ email = "' OR '1'='1" → toți userii
sql`SELECT * FROM users WHERE email = ${email}` // ✓ parametru — trimis separat de queryTemplate-ul sql`...` din @neondatabase/serverless (folosit în aplicația asta), ORM-urile și query builder-ele trimit valorile ca parametri ($1, $2), niciodată ca text.
Pe scurt
- Tabele cu coloane tipate, legate prin primary / foreign keys.
SELECT … WHERE … ORDER BY … LIMIT,INSERT,UPDATE … WHERE,DELETE … WHERE;JOINpentru relații.- Mereu query-uri parametrizate — niciodată input lipit în text.