LearnContact
Lesson 6420 min read

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 You Will Learn
  • 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.

Think of it This Way

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.

setup.sql
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);
subquery_in_where.sql
-- Find students who scored above the average
SELECT name, marks
FROM students
WHERE marks > (SELECT AVG(marks) FROM students);
Result
+-------+-------+
| name  | marks |
+-------+-------+
| Alex  | 82    |
| Priya | 91    |
+-------+-------+

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.

subquery_in_from.sql
-- Treat a subquery's result as a temporary table
SELECT high_scorers.name, high_scorers.marks
FROM (
    SELECT name, marks
    FROM students
    WHERE marks >= 70
) AS high_scorers
ORDER BY high_scorers.marks DESC;
Result
+-------+-------+
| name  | marks |
+-------+-------+
| Priya | 91    |
| Alex  | 82    |
| Riya  | 70    |
+-------+-------+
Why Use a Subquery in FROM?

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.

correlated_subquery.sql
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_id
SELECT s.name, s.marks, s.grade_id
FROM students s
WHERE s.marks > (
    SELECT AVG(marks)
    FROM students AS s2
    WHERE s2.grade_id = s.grade_id
);
Result
+-------+-------+----------+
| name  | marks | grade_id |
+-------+-------+----------+
| Alex  | 82    | 1        |
| Priya | 91    | 2        |
+-------+-------+----------+

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.

TypeDepends on Outer Row?Runs
Non-CorrelatedNoOnce, independently
CorrelatedYesOnce per outer row

Common Mistakes

Avoid These 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

Can a subquery return more than one column?

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.

Are subqueries slower than JOINs?

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.

Can I nest a subquery inside another subquery?

Yes, subqueries can be nested multiple levels deep, though very deep nesting can hurt readability — the next lesson on CTEs offers a cleaner alternative.

What is the difference between a subquery and a JOIN?

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.

Lesson 64 Completed
  • 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.
Next Lesson →

Common Table Expressions (CTE)