Postgres by Example: Expressions
June 22, 2026 · View on GitHub
An expression is anything PostgreSQL can evaluate to a single value: a literal, a column reference, an arithmetic operation, a function call, a CASE, even another SELECT that returns one value. Expressions can appear almost anywhere — in the select list, in WHERE, in ORDER BY, in GROUP BY, in index definitions. Mastering expressions is mastering SQL.
What you'll learn:
- Arithmetic, string, and boolean expressions
- Calling built-in functions in expressions
- Using expressions in
SELECT,WHERE, andORDER BY - Casting between types with
::andCAST(... AS ...) - Naming expression results with
AS
-- Arithmetic and concatenation
SELECT 10 + 2 AS sum, 10 * 2 AS product, 10 / 4 AS int_div, 10 / 4.0 AS real_div;
SELECT 'Hello ' || 'world' AS greeting;
SELECT 'fruit_' || 1 AS labeled; -- numbers are coerced to text for ||
-- Function calls in expressions
SELECT upper(name), length(name), name || ' (#' || id || ')' AS label
FROM fruits ORDER BY id LIMIT 3;
-- Expression in WHERE
SELECT * FROM fruits WHERE id * 2 > 4 ORDER BY id LIMIT 3;
-- Expression in ORDER BY
SELECT id, name FROM fruits ORDER BY length(name) DESC LIMIT 3;
-- Casting
SELECT '42'::integer AS to_int, 42::text AS to_text, '2024-01-15'::date AS to_date;
SELECT CAST(3.7 AS integer) AS rounded_down; -- SQL-standard cast syntax
The || operator concatenates strings. In PostgreSQL, if either operand is not text, it is coerced to text (so 'id_' || 5 works). +, -, *, /, % are the usual arithmetic operators; remember that integer division truncates toward zero.
PostgreSQL casts come in two flavors. value::type is the PostgreSQL-specific shortcut and is the common style. CAST(value AS type) is SQL-standard and reads better when the expression is complex. Both compile to the same thing.
Expressions in WHERE and ORDER BY are evaluated for every candidate row, which means a function call there can prevent index use. WHERE lower(email) = 'a@b.com' cannot use a plain index on email; it can use an expression index defined as CREATE INDEX ON users (lower(email)).
To run:
$ psql -f source/expressions.sql postgres
sum | product | int_div | real_div
-----+---------+---------+----------
12 | 20 | 2 | 2.5
(1 row)
greeting
-------------
Hello world
(1 row)
...
Common pitfalls:
- Integer division returning
0:1 / 2is0. Cast:1.0 / 2,1::numeric / 2, or usenumericcolumns. - Casting strings that don't parse — e.g.
'abc'::integerraises an error. PostgreSQL is strict about types compared to MySQL. - Expressions returning different types in different branches of
CASEcause type-mismatch errors; cast to a common type. - Operators have precedence;
1 + 2 * 3is7. When in doubt, parenthesize.
Tip: When an expression is reused several times in one query, put it in a CTE or derived table once, instead of repeating it. PostgreSQL is smart enough to fold many duplicates, but the code stays cleaner.
Try it: Run SELECT id, name, id || ': ' || name AS label FROM fruits ORDER BY id LIMIT 3;. Then try SELECT name FROM fruits WHERE length(name) > 5;. Then cast: SELECT '3.14'::numeric * 2 AS doubled;.
Source: expressions.sql
Next: Numeric Types
Home: Postgres by Example