Generated Columns#
A generated column is computed from other columns. There are 2 kinds:
Stored Generated Columns:
Computed when they are inserted / updated.
Occupy storage like normal columns.
Virtual Generated Columns:
Computed when they are read.
Occupy no storage.
Not yet implemented in postgres.
To create a generated column, use the GENERATED ALWAYS AS clause in CREATE TABLE. The keyword STORED must be specified to choose the stored kind of generated column:
mydb=> CREATE TABLE roadtrip (
mydb(> start_location text,
mydb(> start_time timestamp,
mydb(> end_location text,
mydb(> end_time timestamp,
mydb(> duration interval GENERATED ALWAYS AS (end_time - start_time) STORED
mydb(> );
CREATE TABLE
mydb=> INSERT INTO roadtrip (start_location, start_time, end_location, end_time)
mydb-> VALUES ('Malindi', '2023-08-01 09:12', 'Changamwe', '2023-08-01 10:55');
INSERT 0 1
A generated column can’t be written to directly. But the keyword DEFAULT may be specified in INSERT and UPDATE commands:
mydb=> INSERT INTO roadtrip (start_location, start_time, end_location, end_time, duration)
mydb-> VALUES ('Nairobi', '2023-08-04 06:04', 'Naivasha', '2023 08-04 07:19', '1:15:00');
ERROR: cannot insert a non-DEFAULT value into column "duration"
DETAIL: Column "duration" is a generated column.
mydb=> INSERT INTO roadtrip (start_location, start_time, end_location, end_time, duration)
VALUES ('Nairobi', '2023-08-04 06:04', 'Naivasha', '2023 08-04 07:19', DEFAULT);
INSERT 0 1
mydb=> SELECT * FROM roadtrip;
start_location | start_time | end_location | end_time | duration
----------------+---------------------+--------------+---------------------+----------
Malindi | 2023-08-01 09:12:00 | Changamwe | 2023-08-01 10:55:00 | 01:43:00
Nairobi | 2023-08-04 06:04:00 | Naivasha | 2023-08-04 07:19:00 | 01:15:00
(2 rows)
Column default |
Generated column |
|---|---|
Evaluated once, on insert |
Updated whenever the row changes |
May not refer to other columns |
Usually refers to other columns |
Can use volatile functions e.g. |
Cannot use volatile functions |
Rules#
The generation expression can only use immutable functions, and cannot use subqueries or reference anything other than the current row.
A generation expression cannot reference another generated column.
A generation expression cannot reference a system column, except
tableoid.A generated column cannot have a column default or identity definition.
A generated column cannot be part of a partition key.
Foreign tables can have generated columns (
CREATE FOREIGN TABLE).For inheritance:
If a parent column is a generated column, a child column must also be a generated column using the same expression. In the definition of the child column, leave off the GENERATED clause, as it will be copied from the parent.
In case of multiple inheritance, if one parent column is a generated column, then all parent columns must be generated columns and with the same expression.
If a parent column is not a generated column, a child column may be defined to be a generated column or not.
Generated columns maintain access privileges separately from their underlying base columns. You can arrange for a particular role to only read from a generated column but not from the underlying base columns.
Generated columns are updated after BEFORE triggers have run. Changes made to base columns in a BEFORE trigger will be reflected in generated columns. However, it is not allowed to access generated columns in BEFORE triggers.