The WITH clause lets you define a temporary, named result set (CTE) that can be referenced multiple times in the same statement.
A Common Table Expression (CTE) created with the WITH
clause produces a temporary, reusable result set that exists only for the duration of the query. It simplifies complex subqueries, improves readability, and supports recursion.
Start with WITH cte_name AS (SELECT ...)
, then write your main query referencing cte_name
. The CTE runs first; its rows feed the outer query.
Use multiple CTEs when the main query requires several intermediate steps—calculations, filters, or aggregates—that would otherwise repeat or clutter the statement. Separate each CTE with a comma.
This pattern isolates logic: one CTE to filter recent customers, another to total their orders, followed by the final SELECT.
Yes for readability and reuse, but CTEs are not always faster. PostgreSQL materializes large or recursive CTEs unless you add WITH ... AS MATERIALIZED/NOT MATERIALIZED
(v12+).
Add RECURSIVE
after WITH
. Supply an anchor SELECT and a UNION ALL that references the CTE itself. PostgreSQL iterates until no new rows appear—ideal for hierarchies.
1) Name CTEs descriptively. 2) Keep each CTE focused on one task. 3) Use NOT MATERIALIZED
for small CTEs that benefit from inlining. 4) Index base tables, not CTEs; they’re temporary.
No. CTEs make queries readable but can be materialized, adding overhead. Use NOT MATERIALIZED
or rewrite as subqueries when speed is critical.
CTEs live only for one statement and require no explicit cleanup, while temporary tables persist for a session and can be indexed or reused across queries.
Yes. PostgreSQL allows UPDATE ... FROM cte_name
or returning rows from a CTE into an UPDATE
/DELETE
/INSERT
.