Skip to main content

Common Table Expressions (CTE)

A CTE (WITH) lets you break a complex query into named steps. This improves reviewability and reduces repeated subqueries.

CTE Workflow

flowchart LR
A[Base tables] --> B[CTE step 1]
B --> C[CTE step 2]
C --> D[Final SELECT]

Syntax and Usage

PatternUse caseExample
Single CTEOne reusable intermediate setWITH recent_orders AS (...) SELECT ...
Multiple CTEsMulti-step transformationsWITH a AS (...), b AS (...) SELECT ...
WITH recent_orders AS (
SELECT customer_id, total_amount
FROM orders
WHERE order_date >= '2026-01-01'
)
SELECT customer_id, SUM(total_amount) AS total_spend
FROM recent_orders
GROUP BY customer_id;

Practical Example

WITH paid_orders AS (
SELECT customer_id, total_amount
FROM orders
WHERE status = 'paid'
),
ranked_customers AS (
SELECT customer_id,
SUM(total_amount) AS spend
FROM paid_orders
GROUP BY customer_id
)
SELECT customer_id, spend
FROM ranked_customers
WHERE spend >= 10000
ORDER BY spend DESC;
customer_idspend
102424300.00
203113120.00

Common Pitfalls

PitfallConsequencePrevention
Treating CTE as persisted objectQuery fails outside statementRemember CTE scope is one statement
Over-stacking too many CTE layersHard to maintain query plansKeep 2-4 meaningful layers, then refactor
Ignoring indexes on base tablesSlow CTE executionTune source table indexes used in joins/filters

Quick Reference

WITH cte AS (SELECT ...)
SELECT ... FROM cte;

WITH a AS (...), b AS (...)
SELECT ... FROM b;

What's Next