Subqueries
Learn what a subquery is, how to nest queries inside WHERE and FROM clauses, and the difference between correlated and non-correlated subqueries.
Introduction
So far, every query you have written has stood on its own. But sometimes the answer to a question depends on the answer to another question first — "which students scored above the class average?" requires knowing the average before you can compare anything to it.
A subquery lets you nest one query inside another, so the inner query's result feeds directly into the outer query. This lesson covers subqueries in a WHERE clause, subqueries in a FROM clause, and the distinction between correlated and non-correlated subqueries.
- What a subquery is and how it is nested inside another query.
- How to use a subquery inside a WHERE clause.
- How to use a subquery inside a FROM clause as a temporary table.
- The difference between correlated and non-correlated subqueries.
What is a Subquery?
A subquery (or inner query) is a complete SELECT statement written inside another query, usually surrounded by parentheses. The database runs the subquery, and its result is used by the outer (main) query.
A subquery answers a smaller question first, and hands that answer to the outer query, which then uses it to answer the bigger question.
Subquery in a WHERE Clause
The most common use of a subquery is inside a WHERE clause, to compare each row against a value calculated by another query — such as an average, maximum, or a list of matching IDs.
CREATE TABLE students ( student_id INT PRIMARY KEY, name VARCHAR(100), marks INT);
INSERT INTO students VALUES (1, 'Alex', 82), (2, 'Priya', 91), (3, 'Sam', 58), (4, 'Riya', 70);-- Find students who scored above the averageSELECT name, marksFROM studentsWHERE marks > (SELECT AVG(marks) FROM students);Click Run to see what this code prints.
Here, the inner query (SELECT AVG(marks) FROM students) runs first and returns a single number — the average of all marks (75.25) — and the outer query then compares every row's marks against that number.
Subquery in a FROM Clause
A subquery can also appear in the FROM clause, where its result is treated as if it were a real, temporary table that the outer query can select from, filter, or join against. A subquery used this way must be given an alias.
-- Treat a subquery's result as a temporary tableSELECT high_scorers.name, high_scorers.marksFROM ( SELECT name, marks FROM students WHERE marks >= 70) AS high_scorersORDER BY high_scorers.marks DESC;Click Run to see what this code prints.
This is useful when you need to filter or aggregate data first, and then run a second, separate operation (like sorting, further filtering, or joining) on that already-processed result.
Correlated vs Non-Correlated Subqueries
A non-correlated subquery runs completely on its own — it does not depend on the outer query at all, and MySQL can evaluate it just once. Both examples above are non-correlated: the average, and the filtered list, are each calculated independently of any specific outer row.
A correlated subquery, by contrast, references a column from the outer query, so it must be re-evaluated once for every row the outer query considers.
CREATE TABLE grades ( grade_id INT PRIMARY KEY, grade_name VARCHAR(10));
ALTER TABLE students ADD COLUMN grade_id INT;UPDATE students SET grade_id = 1 WHERE student_id IN (1, 3);UPDATE students SET grade_id = 2 WHERE student_id IN (2, 4);INSERT INTO grades VALUES (1, '10th'), (2, '11th');
-- Correlated subquery: references the outer query's s.grade_idSELECT s.name, s.marks, s.grade_idFROM students sWHERE s.marks > ( SELECT AVG(marks) FROM students AS s2 WHERE s2.grade_id = s.grade_id);Click Run to see what this code prints.
This inner subquery cannot run just once, because s.grade_id changes for every row the outer query examines — it must recompute the average for each grade group separately, which is exactly what "correlated" means.
| Type | Depends on Outer Row? | Runs |
|---|---|---|
| Non-Correlated | No | Once, independently |
| Correlated | Yes | Once per outer row |
Common Mistakes
- Forgetting to give a FROM-clause subquery an alias, which MySQL requires.
- Writing a subquery that returns multiple rows where the outer query expects a single value (e.g., with = instead of IN).
- Overusing correlated subqueries on large tables, since they can be re-run for every single outer row and hurt performance.
- Confusing a correlated subquery for a non-correlated one, leading to unexpected results.
Best Practices
- Use non-correlated subqueries whenever the inner logic does not depend on the outer row.
- Always alias subqueries used in a FROM clause.
- Prefer JOINs over correlated subqueries when performance matters and the same result is achievable.
- Test the inner subquery by running it on its own first, to confirm it returns what you expect.
Frequently Asked Questions
Yes, especially when used in a FROM clause. A subquery used with = or IN in a WHERE clause, however, is usually expected to return a single column.
It depends. Non-correlated subqueries are often just as fast as an equivalent JOIN, but correlated subqueries can be slower since they may run once per outer row.
Yes, subqueries can be nested multiple levels deep, though very deep nesting can hurt readability — the next lesson on CTEs offers a cleaner alternative.
A JOIN combines rows from two tables side by side. A subquery calculates or filters a result first, then feeds that single result into the outer query.
Key Takeaways
- A subquery is a query nested inside another query, usually in parentheses.
- A subquery in a WHERE clause compares each row against a calculated value, like an average.
- A subquery in a FROM clause is treated as a temporary table and must be given an alias.
- A non-correlated subquery runs independently; a correlated subquery re-runs for every outer row.
Summary
Subqueries let you answer a smaller question first and feed that answer into a bigger query, whether inside a WHERE clause for comparisons or inside a FROM clause to treat a result as a temporary table.
In this lesson, you learned how to write subqueries in both WHERE and FROM clauses, and the difference between correlated and non-correlated subqueries. Next, you will learn about Common Table Expressions, a cleaner way to write many of these same queries.
- You understand what a subquery is.
- You can write a subquery inside a WHERE clause.
- You can write a subquery inside a FROM clause as a temporary table.
- You can distinguish correlated from non-correlated subqueries.
- You are ready to learn about Common Table Expressions.