By WebNest Studio Engineering Team
Database and SQL Tutorial
SQL Subqueries
A subquery is a complete SELECT statement nested inside another SQL statement, used to compute an intermediate result that the outer query then filters, joins against, or selects from. Subqueries let you express multi-step logic — "find the average, then find rows above it" — in a single SQL statement.
Why it matters
Some questions need the answer to another question first: who earns more than the average, which customers have ordered a particular product. A subquery puts one query inside another to express that directly. Knowing when a subquery is the clearest tool, and when a join does the same job better, is part of writing good SQL.
Scalar Subqueries
A scalar subquery returns exactly one row and one column — a single value — and can be used anywhere a single value is expected, such as in a comparison inside WHERE or as a computed column in SELECT. For example, comparing a salary against the company-wide average salary computed by a nested SELECT AVG(salary).
Correlated Subqueries
A correlated subquery references a column from the outer query, so it is logically re-evaluated once for each row the outer query processes, rather than computed just once. This makes it possible to express per-row comparisons, such as "find employees earning more than the average salary in their own department" (as opposed to the company-wide average).
Subquery in WHERE vs. Subquery in FROM
A subquery in WHERE (often with IN, EXISTS, or a comparison operator) filters which outer rows qualify. A subquery in FROM (sometimes called a derived table or inline view) is treated as a temporary, named table that the outer query can select from and join against just like any real table — useful for pre-aggregating or pre-filtering data before the outer query works with it.
Examples
A scalar subquery in WHERE, comparing each salary to the overall average
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
Returns 1 row: ('Asha Rao', 72000) — assuming the overall average salary is 65000.
A subquery used in the FROM clause as a derived table
SELECT dept_summary.department, dept_summary.avg_salary
FROM (
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
) AS dept_summary
WHERE dept_summary.avg_salary > 60000;
Returns 1 row: ('Engineering', 68000.00)
Common Mistakes
- Writing a subquery expected to return one value but that can actually return multiple rows, causing a runtime error when used with "=" instead of IN or a set-aware operator.
- Using a correlated subquery inefficiently on very large tables without realizing it may be logically re-executed once per outer row, which can be far slower than an equivalent JOIN.
- Forgetting to alias a derived table (subquery in FROM) — most databases require every subquery in FROM to have a name.
- Reaching for a subquery when a simple JOIN or aggregate query would express the same logic more clearly and often faster.
Exercise
Return the names of the employees who earn more than the average salary of all employees.
Expected output: name then Ravi
CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, salary INTEGER);
INSERT INTO employees (id, name, salary) VALUES
(1, 'Asha', 50000),
(2, 'Ravi', 60000),
(3, 'Zoya', 40000);
-- TODO: names of employees earning more than the average salary
Show hints
- The average is itself a query:
SELECT AVG(salary) FROM employees. - Put that query in parentheses on the right-hand side of the comparison in
WHERE.
Show solution
CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, salary INTEGER);
INSERT INTO employees (id, name, salary) VALUES
(1, 'Asha', 50000),
(2, 'Ravi', 60000),
(3, 'Zoya', 40000);
SELECT name
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
Quick quiz
1. What is a scalar subquery?
- A. A subquery that returns a table
- B. A subquery in the FROM clause
- C. A subquery that runs twice
- D. A subquery that returns exactly one value
Show answer
D. It can be used wherever a single value is allowed, such as in a comparison.
2. What makes a subquery "correlated"?
- A. It refers to a column of the outer query, so it is evaluated for each outer row
- B. It uses a join
- C. It returns several columns
- D. It is written in the FROM clause
Show answer
A. A non-correlated subquery can be run once, by itself.
3. Which operator tests whether a subquery returns at least one row?
- A. IN
- B. EXISTS
- C. ANY
- D. LIKE
Show answer
B. EXISTS stops as soon as it finds one matching row.
Interview questions
What is the difference between a subquery and a join?
Show answer
A join combines columns from several tables into one result. A subquery uses the result of one query inside another, as a value, a list or a derived table. Many questions can be written either way; a join is needed when columns from both tables must appear in the output, while a subquery is often clearer for "is there a matching row" or "compare with an aggregate". Modern query planners frequently execute the two forms in the same way.
How would you find the second highest salary?
Show answer
One way is a subquery: SELECT MAX(salary) FROM employees WHERE salary < (SELECT MAX(salary) FROM employees). Another is to sort the distinct salaries in descending order and skip one: SELECT DISTINCT salary FROM employees ORDER BY salary DESC LIMIT 1 OFFSET 1. With window functions, DENSE_RANK() OVER (ORDER BY salary DESC) gives a rank that generalises to the Nth highest.
Key Points to Remember
- A scalar subquery returns a single value and can be used wherever a single value is expected.
- A correlated subquery references the outer query's columns and is conceptually evaluated per outer row.
- Subqueries can appear in WHERE (to filter rows) or in FROM (as a named derived table to select and join against).
- Many subqueries can be rewritten as JOINs or aggregate queries, sometimes with better performance and readability.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs your SQL on SQLite in your browser. Standard SQL works; a few features that exist only in PostgreSQL or MySQL do not. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a project environment on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering