Generated / Computed Columns
Define table columns whose values are automatically derived from an expression over other columns.
computed columns generated columns virtual columns stored generated columns
columns expressions virtual stored create table alter table
| Database | Status | Syntax Family | Min Version |
|---|---|---|---|
| PostgreSQL | partial | generated-always-as | 12 |
| MySQL | full | generated-always-as | 5.7 |
| MariaDB | full | generated-always-as | 5.2 |
| Oracle | full | generated-always-as | 11g |
| SQL Server | full | as-expression | - |
| SQLite | full | generated-always-as | 3.31.0 |
| Redshift | none | - | - |
| DB2 | full | generated-always-as | - |
| Snowflake | none | - | - |
| BigQuery | none | - | - |
Compare Databases
Database Details
PostgreSQL
partial
CREATE TABLE orders (
quantity INT,
unit_price NUMERIC,
total NUMERIC GENERATED ALWAYS AS (quantity * unit_price) STORED
);- STORED only. The expression must be immutable (no volatile functions, other tables, or subqueries) and cannot reference another generated column.
Docs: Generated Columns
MySQL
full
CREATE TABLE orders (
quantity INT,
unit_price DECIMAL(10,2),
total DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED
);- Default is VIRTUAL; STORED is opt-in. Both can be indexed.
- GENERATED ALWAYS is optional; AS (expr) alone is accepted.
MariaDB
full
CREATE TABLE orders (
quantity INT,
unit_price DECIMAL(10,2),
total DECIMAL(10,2) AS (quantity * unit_price) PERSISTENT
);- Default is VIRTUAL. PERSISTENT is MariaDB's term for STORED; STORED is also accepted since 10.2.
Oracle
full
CREATE TABLE orders (
quantity NUMBER,
unit_price NUMBER,
total NUMBER GENERATED ALWAYS AS (quantity * unit_price)
);- VIRTUAL only since 11g; no STORED option.
- AS (expr) shorthand is accepted; virtual columns can be indexed and used in constraints.
SQL Server
full
CREATE TABLE orders (
quantity INT,
unit_price DECIMAL(10,2),
total AS (quantity * unit_price) PERSISTED
);- Spelling is AS (expr) [PERSISTED], not GENERATED ALWAYS AS.
- VIRTUAL is the default; PERSISTED materializes the value on write and is required (along with a deterministic expression) for indexing.
Docs: Computed Columns
SQLite
full
CREATE TABLE orders (
quantity INTEGER,
unit_price REAL,
total REAL GENERATED ALWAYS AS (quantity * unit_price) STORED
);- Default is VIRTUAL; STORED is opt-in.
- Not usable as a PRIMARY KEY but can participate in UNIQUE and other constraints.
- VIRTUAL columns cannot always be indexed directly; an expression index on the underlying columns is the usual workaround.
Docs: Generated Columns
Redshift
none
- No expression-based generated columns. IDENTITY columns handle auto-increment but not arbitrary expressions.
Docs: CREATE TABLE
DB2
full
CREATE TABLE orders (
quantity INT,
unit_price DECIMAL(10,2),
total DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price)
);- GENERATED ALWAYS AS (expr) is virtual; adding STORED materializes it on write.
- Expressions may use arithmetic, function calls, and CASE.
Docs: Generated Column
Snowflake
none
- Not supported on standard tables. The AS (expr) column syntax is only available on external-table virtual columns.
- Use a view or Dynamic Table to expose derived values.
Docs: CREATE TABLE
BigQuery
none
- Not supported. Use a view or materialized view for derived columns.