Building complex queries in readable layers — and when to use each approach
Real-world SQL questions require multiple steps — filter, aggregate, rank, then filter again. Subqueries and CTEs let you name intermediate results and build queries in layers. CTEs in particular transform deeply nested unreadable SQL into a step-by-step structure that reads almost like code comments, and are preferred over subquery nesting for readability.
A subquery is a query embedded inside another query — either in FROM (derived table), WHERE (scalar or list subquery), or SELECT (correlated subquery). A CTE (Common Table Expression) is like giving a subquery a name at the top of the query. They're often equivalent in what they compute, but CTEs are almost always more readable.
Think of CTEs as named intermediate steps you build up, left to right, and then compose in the final SELECT — like variable assignment in a programming language.
Correlated subqueries run once per outer row — they can be very slow on large tables. Rewrite them as a join or CTE with a pre-computed aggregate when performance matters.
Recursive CTEs are the standard way to traverse hierarchical data — org charts, category trees, bill of materials. The anchor member (base case) runs once; the recursive member repeats until no new rows are added.