Skip to main content

Common Table Expressions

A Common Table Expression (CTE) is a named temporary result set within a single statement.

CTEs improve readability by decomposing queries into logical steps.

Core Concepts

flowchart TD
A[WITH cte AS (...)] --> B[CTE produces intermediate rows]
B --> C[Main query references cte]
C --> D[Final result]
CTE benefitWhy it helps
Named stepsEasier to read and review
Reuse in one queryAvoid repeated subquery text
Better structureClear pipeline of transformations
WITH category_totals AS (
SELECT category, SUM(amount) AS total_amount
FROM payments_agg
GROUP BY category
)
SELECT category, total_amount
FROM category_totals
ORDER BY total_amount DESC;
categorytotal_amount
tools300.0
cloud130.0

Code Examples

-- CTE replacing nested subquery style.
WITH avg_price AS (
SELECT AVG(price) AS value
FROM products_sub
)
SELECT p.product_id, p.name, p.price
FROM products_sub AS p, avg_price AS a
WHERE p.price > a.value
ORDER BY p.price DESC;
product_idnameprice
3Pro Keyboard150.0
2Keyboard100.0
-- CTE with aggregation and post-filter.
WITH city_counts AS (
SELECT city, COUNT(*) AS cnt
FROM contacts_count
GROUP BY city
)
SELECT city, cnt
FROM city_counts
WHERE cnt >= 2
ORDER BY city;
citycnt
Berlin2
Tokyo2

SQLite-Specific Nuances

SQLite Nuance

SQLite supports non-recursive and recursive CTEs.

Start with non-recursive CTEs for readability before introducing recursion.

Common Pitfalls / Best Practices

Pitfall

Using too many one-off CTE layers for simple queries, making SQL longer without clarity gains.

Best Practice

Use CTEs when they improve naming and readability of meaningful intermediate steps.

Quick Challenge

Write a CTE that computes average amount from payments_agg, then selects payments above that average.

View Solution
WITH avg_amount AS (
SELECT AVG(amount) AS value
FROM payments_agg
)
SELECT payment_id, category, amount
FROM payments_agg, avg_amount
WHERE amount > avg_amount.value
ORDER BY amount DESC;
payment_idcategoryamount
1tools120.0
5tools100.0