Skip to content
PrepMint

SQL

SQL Subqueries

Nesting queries inside queries — scalar, correlated and FROM-clause subqueries, the operators that pair with them, and when a subquery beats a join.

3 questions
Medium· 3

Last reviewed

Recommended

SQL Subqueries — Timed Test (3 questions)

TimedMedium3 questions · 3 min
Start test

No account needed. Answers and explanations arrive when you submit.

What this topic tests

The mix every SQL Subqueries set is built to, and the questions published against it so far. Nothing here is hidden before you start.

SQL Subqueries — target difficulty mix and published question count per level
LevelTarget sharePublished
Easy40%0
Medium40%3
Hard20%0
Total3

SQL Subqueries — the theory

A subquery is a query nested inside another SQL query, used to compute an intermediate result that the outer query then uses — a technique that allows expressing more complex logic than a single flat query could handle on its own.

Basic concept. A subquery is written inside parentheses and can appear in various parts of an outer query: in the WHERE clause to filter rows based on a computed condition, in the SELECT clause to compute a derived value, or in the FROM clause to treat the subquery's result as if it were a table. The database evaluates the subquery (in many cases) and then uses its result as part of evaluating the outer query.

Subqueries in `WHERE` clauses. One of the most common uses is filtering rows in an outer query based on a value or set of values computed by a subquery — for example, finding all orders placed by customers who live in a specific city, where the list of matching customer IDs is computed by a subquery against the customers table, and the outer query then filters orders against that computed list.

Scalar subqueries. A scalar subquery returns exactly one value (one row, one column), and can be used anywhere a single value would be expected — for example, comparing a column against a subquery that computes an average, like finding all products priced above the average price of all products.

Correlated subqueries. A correlated subquery references a column from the outer query, meaning it can't be evaluated independently — it's effectively re-evaluated for each row the outer query considers, referencing that row's specific values. This makes correlated subqueries more powerful for row-by-row comparisons, but also generally more expensive to execute than a non-correlated subquery, since the subquery logic runs repeatedly rather than once.

Subqueries versus joins. Many tasks that can be accomplished with a subquery can also be expressed using a join, and the two approaches sometimes have different performance characteristics depending on the specific database and query. As a general pattern, joins are often preferred when you need to retrieve columns from both tables in the result, while subqueries are often clearer when you only need to filter or compute a value based on a relationship between tables without needing to display columns from both.

Subqueries in the `FROM` clause. A subquery can also be used as if it were a table in the FROM clause (sometimes called a derived table), letting you first compute an intermediate result set and then query against that result as though it were a regular table — useful for breaking a complex query into more understandable, composable pieces.

Common pitfalls. A common mistake is using a subquery that returns multiple rows in a context that expects a single value (a scalar context), which causes an error. Another is writing an unnecessarily correlated subquery when a simpler, non-correlated version (or a join) would produce the same result with better performance.

The operators that pair with subqueries. Several SQL operators exist largely to work with subquery results. IN checks whether a value appears in the set a subquery returns, and NOT IN checks the opposite — with the caveat that a NULL in the subquery's result can make NOT IN behave in unintuitive ways. EXISTS checks only whether a subquery returns any rows at all, which often pairs naturally with correlated subqueries and can be more efficient because the database can stop at the first match. ANY and ALL compare a value against every value a subquery returns — "greater than all of them," "equal to any of them" — completing a small vocabulary worth knowing as a set.

A worked example in words. Consider "find employees who earn more than their department's average salary." The outer query walks the employees; for each one, a correlated subquery computes the average salary of that employee's department; the WHERE clause keeps rows where the employee's salary exceeds that computed average. Reasoning through it inside-out — what the inner query computes, what single value or set it hands back, and how the outer query uses it — is the reliable way to read any subquery, and writing them follows the same order: inner query first, tested on its own, then wrapped.

Readability and modern alternatives. When subqueries nest more than a level or two deep, queries become genuinely hard to read. Modern SQL offers common table expressions — the WITH clause — which let you name an intermediate result and then use it like a table, expressing the same logic as stacked FROM-clause subqueries but in a flat, top-to-bottom order that reads like a sequence of steps. Knowing subqueries remains essential — CTEs are built on exactly the same concept — but recognizing when a WITH clause would say the same thing more clearly is part of writing SQL other people can maintain.

Understanding subqueries — how to write them, where they can be used, and when they're the clearer choice compared to a join — is an important step beyond basic single-table queries toward writing more expressive, capable SQL for real-world, multi-table data problems.

Sample questions

Three questions from this topic, with the answer and the reasoning shown.

Q1MediumWhat is a scalar subquery?
  • A subquery that returns exactly one valueCorrect
  • A subquery that always returns an entire table
  • A subquery that can never be used in a WHERE clause
  • A subquery that only works with text data

Explanation

A scalar subquery is a SELECT wrapped in parentheses that yields one row and one column, and the engine substitutes that result into the surrounding expression as if a literal sat there. PostgreSQL states the shape directly: "A scalar subquery is an ordinary SELECT query in parentheses that returns exactly one row with one column." MySQL calls it a scalar operand, usable almost anywhere a single column value or literal is legal.

The consequence shows up at runtime, and dialects differ. If the inner query returns two rows for some input, PostgreSQL raises an error rather than picking one; SQLite quietly takes the first row. A scalar subquery that can return two rows is a latent bug either way.

Option B describes a different construct: a subquery returning a whole table is a derived table in FROM, or the operand of IN, which is exactly what a scalar subquery may not be. Option C reverses reality: WHERE is where scalar subqueries most often live; the genuine restrictions sit where a literal is mandatory, such as LIMIT. Option D confuses shape with data type, which can be anything the column holds.

Open this question on its own page

Q2MediumWhat makes a subquery 'correlated'?
  • It references a column from the outer query, so it's re-evaluated per outer rowCorrect
  • It can only be written in all capital letters
  • It cannot be used with the WHERE clause
  • It always runs faster than a non-correlated subquery

Explanation

Correlation is a matter of scope, not syntax. A subquery becomes correlated the moment it references a column belonging to a table in the enclosing query, a name its own FROM clause never mentions. MySQL defines it as "a subquery that contains a reference to a table that also appears in the outer query", and PostgreSQL notes that such variables act as constants during any one evaluation of the subquery.

Because that borrowed column changes from one outer row to the next, the inner query cannot be computed once and cached. SQLite states the runtime consequence plainly: "A correlated subquery is reevaluated each time its result is required. An uncorrelated subquery is evaluated only once and the result reused as necessary."

That makes option D the costly misconception. Re-running an inner query per outer row is generally more work, not less, which is why PostgreSQL and MySQL both rewrite such subqueries into joins and semijoins where they can. Option C is false; correlated subqueries live in WHERE constantly, usually under EXISTS. Option B mistakes typography for semantics: SQL keywords are case-insensitive, and letter case has no bearing on correlation.

Open this question on its own page

Q3MediumWhen is a join often preferred over a subquery?
  • When you need to retrieve columns from both tables in the resultCorrect
  • When you never need any data from either table
  • Joins can never be used alongside subqueries
  • When the tables involved have no relationship at all

Explanation

The deciding factor is the SELECT list. A subquery in WHERE answers a yes-or-no question about the inner table and then vanishes; PostgreSQL notes that for EXISTS, "the output list of the subquery is normally unimportant" because only the existence of a matching row matters. So a filter such as WHERE EXISTS (SELECT 1 FROM orders WHERE orders.customer_id = customers.id) can identify customers who ordered, but it cannot place the order date in the result. A join can. SQLite describes the joined dataset as carrying all the columns of the left-hand dataset followed by all the columns of the right-hand dataset, which is the property required when both tables must appear in the output.

Resist the folklore that joins are inherently faster. PostgreSQL documents that the planner merges sub-queries into upper queries, and MySQL transforms IN and EXISTS predicates into semijoins, so the two forms frequently compile to the same plan. Option C fails on its face, since joins and subqueries routinely appear in one statement. Options B and D describe cases where no join is warranted at all.

Open this question on its own page

Practise all 3 questions

Every published question in SQL Subqueries, with its answer and explanation.