Ce face rowid și INTEGER PRIMARY KEY
Fiecare rând dintr-un tabel obișnuit are un număr întreg unic, rowid, chiar dacă nu l-ai declarat. Datele sunt păstrate pe disc în ordinea lui, așa că o căutare după rowid este cea mai rapidă căutare posibilă. Coloana se poate citi și cu numele oid sau _rowid_.
Dacă declari o coloană exact INTEGER PRIMARY KEY, ea devine un alt nume pentru rowid. Când inserezi fără valoare (sau cu NULL), SQLite îi dă automat valoarea cea mai mare din tabel plus 1. Funcția last_insert_rowid() îți spune ce valoare a primit ultimul rând inserat pe conexiunea curentă.
Atenție la scriere: doar INTEGER PRIMARY KEY devine alias. INT PRIMARY KEY sau BIGINT PRIMARY KEY creează o cheie primară obișnuită, separată de rowid, care, din motive istorice, acceptă chiar și NULL.
Ce returnează
last_insert_rowid() returnează rowid-ul ultimului rând inserat, ca întreg.
Exemple
Exemplul 1: rowid-ul ascuns
Tabelul nu are nicio coloană de identificare, dar fiecare rând are totuși un rowid. SELECT * nu îl afișează; trebuie cerut explicit.
CREATE TABLE note (elev TEXT, nota INTEGER);
INSERT INTO note VALUES ('Ana', 9), ('Mihai', 7);
SELECT rowid, * FROM note;
Rezultat
╭───────┬───────┬──────╮
│ rowid │ elev │ nota │
╞═══════╪═══════╪══════╡
│ 1 │ Ana │ 9 │
│ 2 │ Mihai │ 7 │
╰───────┴───────┴──────╯
Exemplul 2: INTEGER PRIMARY KEY primește valori automat
Primele două rânduri primesc 1 și 2. După ce inserăm explicit id-ul 10, următorul rând primește 11 (cel mai mare plus 1). După ștergerea lui 11, valoarea 11 este refolosită: fără AUTOINCREMENT, un id eliberat la final poate fi dat din nou.
CREATE TABLE elevi (id INTEGER PRIMARY KEY, nume TEXT);
INSERT INTO elevi (nume) VALUES ('Ana'), ('Mihai');
INSERT INTO elevi (id, nume) VALUES (10, 'Ioana');
INSERT INTO elevi (nume) VALUES ('Radu');
SELECT last_insert_rowid() AS ultimul_id;
DELETE FROM elevi WHERE id = 11;
INSERT INTO elevi (nume) VALUES ('Elena');
SELECT rowid AS r, id, nume FROM elevi;
Rezultat
╭────────────╮
│ ultimul_id │
╞════════════╡
│ 11 │
╰────────────╯
╭────┬────┬───────╮
│ r │ id │ nume │
╞════╪════╪═══════╡
│ 1 │ 1 │ Ana │
│ 2 │ 2 │ Mihai │
│ 10 │ 10 │ Ioana │
│ 11 │ 11 │ Elena │
╰────┴────┴───────╯
Exemplul 3: INT PRIMARY KEY nu este alias
Cu INT în loc de INTEGER, coloana id este o coloană separată: nu primește valoare automat și a rămas NULL, în timp ce rowid-ul ascuns este 1.
CREATE TABLE clienti (id INT PRIMARY KEY, nume TEXT);
INSERT INTO clienti (nume) VALUES ('Ana');
SELECT rowid AS r, id, typeof(id) AS tip_id, nume FROM clienti;
Rezultat
╭───┬────┬────────┬──────╮
│ r │ id │ tip_id │ nume │
╞═══╪════╪════════╪══════╡
│ 1 │ │ null │ Ana │
╰───┴────┴────────┴──────╯
Greșeli frecvente
- Scrii
id INT PRIMARY KEYși aștepți numere automate. DoarINTEGER PRIMARY KEY(exact acest tip) devine alias pentru rowid. - Te bazezi pe
rowidîntr-un tabel fărăINTEGER PRIMARY KEYca identificator permanent.VACUUMpoate renumerota rowid-urile acestor tabele; declară o coloanăINTEGER PRIMARY KEY. - Citești
last_insert_rowid()din altă conexiune sau după alte inserări. Valoarea este per conexiune și se schimbă la fiecareINSERT; în SQLite 3.35+ poți folosiINSERT ... RETURNING id.
Comenzi înrudite
AUTOINCREMENT: Garantează că un id nu este refolosit niciodată, nici după ștergere; SQLite ține ultima valoare în tabelul sqlite_sequence.WITHOUT ROWID: Creează un tabel fără coloana ascunsă rowid, organizat direct după cheia primară; util pentru chei compuse sau texte scurte.RETURNING: Face ca INSERT, UPDATE sau DELETE să returneze rândurile modificate, de exemplu id-ul generat, fără un SELECT separat.CREATE TABLE: Creează un tabel nou. În SQLite tipul coloanei este opțional și doar sugerează cum se salvează valorile.VACUUM: Reconstruiește fișierul bazei de date: eliberează spațiul rămas după ștergeri și, cu INTO, face o copie compactă.