free-tech

Understanding How PostgreSQL Generated Columns Work


What is a PostgreSQL Generated Column?



Virtual And Stored



Example


The following example creates a table for rectangles, whose area can be calculated as the width times the height.
CREATE TABLE rectangles (
    "id" UUID PRIMARY KEY,
    "width" DECIMAL(3,2), 
    "height" DECIMAL (3,2), 
    "area" DECIMAL(6,4) GENERATED ALWAYS AS ("width" * "height") STORED
);


We use a stored generated column to store the area of the rectangle so that we don't have to perform this mathematical operation in our queries or application layer. By using a generated column rather than a non-generated one, we do not risk having data out-of-sync. E.g. the application layer updates the width or height, but forgets to update the area.

Optionally Add Index


As stated before, one can index these generated columns, which may be useful in situations where you have millions of rows, and want to quickly sort by the area, or just pick the largest/smallest.
CREATE INDEX on rectangles ("area");

Insert Examples


INSERT INTO rectangles ("id", "width", "height") VALUES 
  ('96c90ad7-7fd6-4e7d-87e7-cf9346cd086a', 3.1, 3.2),
  ('96c90af1-9276-456a-948c-cecdf81fdb9d', 4.5, 2.3),
  ('96c90af1-9357-4189-820a-ea11adbe4f20', 6.4, 1.2)
;


Now we can select everything from the rectangles table, which will now show the area.
SELECT * FROM rectangles;

                  id                  | width | height |  area   
--------------------------------------+-------+--------+---------
 96c90ad7-7fd6-4e7d-87e7-cf9346cd086a |  3.10 |   3.20 |  9.9200
 96c90af1-9276-456a-948c-cecdf81fdb9d |  4.50 |   2.30 | 10.3500
 96c90af1-9357-4189-820a-ea11adbe4f20 |  6.40 |   1.20 |  7.6800
(3 rows)
Now we can find the largest rectangle by simply executing:
SELECT * FROM rectangles ORDER BY area DESC limit 1;

                  id                  | width | height |  area   
--------------------------------------+-------+--------+---------
 96c90af1-9276-456a-948c-cecdf81fdb9d |  4.50 |   2.30 | 10.3500
(1 row)

If we didn't have the generated column, we would have to do something like below, which looks very messy/confusing, especially with all the * symbols.
SELECT 
  *, 
  width * height as area 
FROM rectangles 
ORDER BY area 
DESC LIMIT 1;


This query won't work whilst the table has the generated column called area.


Similar Articles


Card image

Docker CLI Commands

Card image

How to Fix the "Your PHP Installation Appears to Be Missing the MySQL Extension Which Is Required by WordPress" Error

Card image

Mysql command lines