Modules / Database / Subquery Lab

Subqueries in SQL

A query inside a query. The inner one runs first and hands its answer to the outer one — except in the correlated case, where it runs again for every single row. Watch that happen.

1 Inner query result
2 Outer query — every row tested against that answer
3 Result

Overview

A scalar subquery returns one value, such as a maximum date. A subquery in FROM acts as a derived table. A subquery in WHERE can test membership or existence. These shapes let one query express a calculation or filter that would otherwise need a separate statement.

Three common shapes

query.sqlSQLite
Result

The inner query produces one row per customer; the outer query filters those results. A CTE can make the same steps easier to name. See common table expressions.

Correlated and uncorrelated

An uncorrelated subquery can be evaluated independently of the current outer row. A correlated subquery refers to a column from that row, as in a test for whether a customer's orders exist. Correlation describes the logic, not necessarily the physical execution: an optimizer may transform or decorrelate it.

For a yes/no existence question, EXISTS often states the intent directly. A JOIN instead returns matching pairs and may multiply outer rows when several matches exist. Choose based on result shape, then inspect the plan if performance matters. See EXISTS, IN, and JOIN.

Check cardinality and NULLs

A scalar subquery should return at most one row; behavior when it returns more than one is engine-specific. PostgreSQL reports an error, while SQLite uses the first result row, so do not rely on accidental multi-row results. NOT IN can produce UNKNOWN if its candidate set contains NULL. Test empty input, duplicate matches, and NULLs when those cases are possible.

Scalar subqueries need one value

A scalar subquery can provide a value in a SELECT list, such as each product's latest price date. Ensure its logic returns no more than one row: use an aggregate, a unique key, or a deterministic ORDER BY with a supported row limit. If there are no rows, many engines return NULL; if there are several, behavior may be an error. A correlated scalar subquery may be evaluated many times or transformed by the optimizer, so inspect the plan on large data.

Choose a shape that matches the result

Use a scalar subquery when one value belongs beside each row, EXISTS when only match existence matters, and a derived table when an intermediate result has its own columns or grain. A subquery in FROM needs an alias in many engines. If the same calculation is difficult to read inline, a CTE can name it. These are readability and semantic distinctions; the optimizer may produce the same physical plan. Measure only after confirming the query returns the intended rows.

Further reading

Predict, then reveal

About to run: switch Kind of Subquery to Correlated - runs once per row. Before it does — what happens to the readout?

Committing to an answer first is the point — the reveal runs the experiment on the visualisation above and reads the real value back, so nothing here is scripted.

Recall check

0 of 3

Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.

  1. What does this module say about “Three common shapes”?

  2. What does this module say about “Correlated and uncorrelated”?

  3. What does this module say about “Check cardinality and NULLs”?

Cheat sheet

Subqueries in SQL

The inner query runs first and hands its answer to the outer one. Scalar, IN-list, derived table, and a correlated subquery re-running once per row.

DATABASE · vizlearn.in/database/subqueries_in_sql.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.