Coloane generate (GENERATED ALWAYS AS) în SQLite

O coloană a cărei valoare este calculată automat dintr-o expresie peste celelalte coloane ale rândului, la citire sau la scriere.

Sintaxă
coloana tip GENERATED ALWAYS AS (expresie) [VIRTUAL | STORED]
coloana tip AS (expresie)   -- formă scurtă, VIRTUAL

Ce face Coloane generate (GENERATED ALWAYS AS)

O coloană generată nu primește valori prin INSERT sau UPDATE: SQLite o calculează din expresia dată, folosind celelalte coloane ale aceluiași rând. Cuvintele GENERATED ALWAYS sunt opționale, deci total AS (pret * cantitate) este suficient.

Există două feluri. VIRTUAL (implicit) calculează valoarea la fiecare citire și nu ocupă loc pe disc. STORED o calculează la fiecare scriere și o salvează în fișier. Ambele pot fi indexate, așa că poți căuta rapid după o valoare calculată.

Expresia poate folosi doar coloane din același rând și funcții deterministe: nu poate conține subinterogări, funcții agregate sau valori care se schimbă, precum datetime('now'). Cu ALTER TABLE ADD COLUMN se pot adăuga doar coloane VIRTUAL.

Parametri

Parametru Descriere
expresie Calculul, scris între paranteze, peste coloanele rândului.
VIRTUAL Implicit. Calculată la citire, nu ocupă spațiu.
STORED Calculată la scriere și salvată pe disc.

Exemple

Exemplul 1: Total și nume normalizat

total este STORED, nume_mic este VIRTUAL. După UPDATE la cantitate, totalul se recalculează singur.

CREATE TABLE comenzi (
  id INTEGER PRIMARY KEY,
  produs TEXT,
  pret INTEGER,
  cantitate INTEGER,
  total INTEGER GENERATED ALWAYS AS (pret * cantitate) STORED,
  nume_mic TEXT AS (lower(produs))
);
INSERT INTO comenzi (produs, pret, cantitate) VALUES ('CAIET', 12, 3), ('Pix', 4, 10);
SELECT * FROM comenzi;

UPDATE comenzi SET cantitate = 5 WHERE id = 1;
SELECT id, cantitate, total FROM comenzi;

Rezultat

╭────┬────────┬──────┬───────────┬───────┬──────────╮
│ id │ produs │ pret │ cantitate │ total │ nume_mic │
╞════╪════════╪══════╪═══════════╪═══════╪══════════╡
│  1 │ CAIET  │   12 │         3 │    36 │ caiet    │
│  2 │ Pix    │    4 │        10 │    40 │ pix      │
╰────┴────────┴──────┴───────────┴───────┴──────────╯
╭────┬───────────┬───────╮
│ id │ cantitate │ total │
╞════╪═══════════╪═══════╡
│  1 │         5 │    60 │
│  2 │        10 │    40 │
╰────┴───────────┴───────╯

Exemplul 2: Index pe o valoare extrasă din JSON

Coloana virtuală oras scoate orașul din textul JSON. Indexul pe ea face căutările după oraș rapide; EXPLAIN QUERY PLAN arată că interogarea folosește indexul.

CREATE TABLE clienti (
  id INTEGER PRIMARY KEY,
  date TEXT,
  oras TEXT AS (date ->> '$.oras')
);
CREATE INDEX idx_clienti_oras ON clienti(oras);
INSERT INTO clienti (date) VALUES ('{"nume":"Ana","oras":"Iași"}'), ('{"nume":"Mihai","oras":"Cluj"}');
SELECT id, oras FROM clienti WHERE oras = 'Iași';
EXPLAIN QUERY PLAN SELECT id FROM clienti WHERE oras = 'Iași';

Rezultat

╭────┬──────╮
│ id │ oras │
╞════╪══════╡
│  1 │ Iași │
╰────┴──────╯
QUERY PLAN
`--SEARCH clienti USING INDEX idx_clienti_oras (oras=?)

Exemplul 3: Coloanele generate în table_xinfo

PRAGMA table_info nu arată coloanele generate; table_xinfo le arată, cu hidden = 2 pentru VIRTUAL și 3 pentru STORED.

CREATE TABLE comenzi (
  pret INTEGER,
  cantitate INTEGER,
  total INTEGER AS (pret * cantitate) STORED,
  eticheta TEXT AS ('Total: ' || total)
);
SELECT name, type, hidden FROM pragma_table_xinfo('comenzi');

Rezultat

╭───────────┬─────────┬────────╮
│   name    │  type   │ hidden │
╞═══════════╪═════════╪════════╡
│ pret      │ INTEGER │      0 │
│ cantitate │ INTEGER │      0 │
│ total     │ INTEGER │      3 │
│ eticheta  │ TEXT    │      2 │
╰───────────┴─────────┴────────╯

Greșeli frecvente

  • Dai o valoare unei coloane generate în INSERT. Primești cannot INSERT into generated column; lasă coloana afară din listă.
  • Încerci ALTER TABLE ... ADD COLUMN ... STORED pe un tabel cu date. Primești cannot add a STORED column; adaugă coloana ca VIRTUAL sau reconstruiește tabelul.
  • Folosești datetime('now') sau random() în expresie. Sunt nedeterministe și nu sunt permise în coloane generate; pentru data inserării folosește DEFAULT.

Comenzi înrudite

  • CREATE TABLE: Creează un tabel nou. În SQLite tipul coloanei este opțional și doar sugerează cum se salvează valorile.
  • ALTER TABLE: Modifică un tabel existent: redenumire, coloane adăugate sau șterse. Schimbarea tipului unei coloane nu se poate face direct.
  • Index pe expresii: Indexează rezultatul unei expresii, de exemplu lower(email) sau un câmp JSON, ca să cauți rapid după valoarea calculată.
  • Operatorii -> și ->>: Prescurtări pentru citirea din JSON: -> întoarce o bucată de JSON, ->> întoarce valoarea SQL, fără ghilimele.
  • PRAGMA table_info: Afișează coloanele unui tabel: poziția, numele, tipul declarat, NOT NULL, valoarea implicită și cheia primară.