Skip to main content

Correlated Subqueries

Correlated subqueries reference columns from the outer query.

That means the inner query is evaluated per outer row context.

Core Concepts

flowchart LR
A[Outer row] --> B[Inner query uses outer values]
B --> C[Condition evaluated]
C --> D[Row kept or filtered]
D --> E[Repeat for next outer row]
Query typeInner query depends on outer row?
Non-correlated subqueryNo
Correlated subqueryYes

Code Examples

-- Setup per-category product prices.
CREATE TABLE products_corr (
product_id INTEGER PRIMARY KEY,
category TEXT NOT NULL,
name TEXT NOT NULL,
price REAL NOT NULL
);

INSERT INTO products_corr (category, name, price)
VALUES
('hardware', 'Mouse', 50.0),
('hardware', 'Keyboard', 100.0),
('hardware', 'Pro Keyboard', 150.0),
('stationery', 'Notebook', 20.0),
('stationery', 'Pen Set', 40.0);
Expected output
Table created and five rows inserted.
-- Products priced above their category average.
SELECT p1.product_id, p1.category, p1.name, p1.price
FROM products_corr AS p1
WHERE p1.price > (
SELECT AVG(p2.price)
FROM products_corr AS p2
WHERE p2.category = p1.category
)
ORDER BY p1.category, p1.price DESC;
product_idcategorynameprice
3hardwarePro Keyboard150.0
5stationeryPen Set40.0
-- Correlated EXISTS pattern (preview).
SELECT DISTINCT p1.category
FROM products_corr AS p1
WHERE EXISTS (
SELECT 1
FROM products_corr AS p2
WHERE p2.category = p1.category
AND p2.price >= 140
)
ORDER BY p1.category;
category
hardware

SQLite-Specific Nuances

SQLite Nuance

Correlated subqueries are expressive, but can be heavier than equivalent joins/CTEs on large datasets.

Use them when they improve clarity for row-wise logic.

Common Pitfalls / Best Practices

Pitfall

Forgetting correlation predicates in the inner query and accidentally comparing against global results.

Best Practice

Alias outer and inner tables clearly (p1, p2) and review the correlation condition first.

Quick Challenge

Return stationery products priced above the stationery category average.

View Solution
SELECT p1.name, p1.price
FROM products_corr AS p1
WHERE p1.category = 'stationery'
AND p1.price > (
SELECT AVG(p2.price)
FROM products_corr AS p2
WHERE p2.category = p1.category
);
nameprice
Pen Set40.0