How to Write Subqueries in SQL
Use subqueries when one query needs the result of another query to filter, compare, calculate, or build derived datasets. This is one of the cleanest ways to express layered SQL logic.
What you’ll build or solve
You’ll learn how to write subqueries in SQL inside WHERE, FROM, and SELECT. You’ll also know when joins may be clearer.
Learn SQL on Mimo
When this approach works best
This approach is the right choice when one step depends on the output of another step.
Common real-world scenarios include:
- Users above average spend
- Orders from top customers
- Latest record per entity
- Derived reporting tables
- Existence checks
This is a bad idea when the logic becomes hard to read and a JOIN or CTE would communicate intent better.
Prerequisites
You only need:
- Basic
SELECT,WHERE, and aggregate knowledge - Comfort reading nested query logic
Step-by-step instructions
Step 1: Place one query inside another
A common use is comparing against an aggregate.
SQL
SELECT *
FROM orders
WHERE total > (
SELECT AVG(total)
FROM orders
);
The inner query runs first.
Its result becomes the comparison value for the outer query.
Subqueries also work in IN.
SQL
SELECT *
FROM users
WHERE user_id IN (
SELECT user_id
FROM orders
WHERE status = 'paid'
);
What to look for:
- Inner query runs first
- Great for comparisons and filtering
- Can return one value or many rows
- Useful in
WHERE,FROM, andSELECT - Joins may read better for reusable logic
Examples you can copy
Above-average price
SQL
SELECT *
FROM products
WHERE price > (
SELECT AVG(price)
FROM products
);
Users with paid orders
SQL
SELECT *
FROM users
WHERE user_id IN (
SELECT user_id
FROM orders
WHERE status = 'paid'
);
Latest login
SQL
SELECT *
FROM logins
WHERE created_at = (
SELECT MAX(created_at)
FROM logins
);
Common mistakes and how to fix them
Mistake 1: Returning multiple rows for scalar comparison
What the reader might do:
SQL
WHERE total > (
SELECT total
FROM orders
)
Why it breaks: the subquery returns many rows.
Corrected approach:
Use aggregates or IN.
Mistake 2: Using subqueries where joins are clearer
What the reader might do:
Nest multiple repeated subqueries.
Why it breaks: the query becomes harder to maintain.
Corrected approach:
Switch to joins or CTEs.
Mistake 3: Ignoring performance on correlated logic
What the reader might do:
Use row-by-row correlated subqueries on huge tables.
Why it breaks: this can be expensive.
Corrected approach:
Consider joins or indexed CTEs.
Troubleshooting
If SQL says “more than one row returned,” switch to IN or aggregate.
If the logic feels repetitive, rewrite as a join.
If performance is slow, inspect correlated subqueries.
If readability matters, use CTEs for named steps.
Quick recap
- Subqueries nest one query inside another
- Inner query runs first
- Great for comparisons and filters
- Use
INfor multi-row results - Prefer joins or CTEs for complex reusable logic
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot