Subqueries


Subqueries (Nested Queries)

Subqueries—also called nested queries—allow you to embed one query inside another. While they are expressive and widely supported, they tend to be harder to read, reuse, and optimize compared to CTEs. In modern engines (PostgreSQL, SQL Server, Snowflake, Databricks, BigQuery, Oracle), CTEs are almost always preferred from a readability and maintainability standpoint.

However, subqueries remain important, especially for inline filtering, simple tests of existence, correlated queries, and when targeting older engines with limited CTE support.


Why Subqueries Are Often Worse Than CTEs

Subqueries are not “terrible,” but they are inferior in several practical ways:

CTEs Improve Readability and Maintainability

  • Subqueries nest logic deeply → harder to understand.

  • CTEs separate logic → readable step-by-step.

CTEs Allow Reuse

A subquery can’t be referenced twice; a CTE can.

CTEs Enable Greedy Optimization (in modern engines)

  • PostgreSQL (since v12), SQL Server, Oracle, BigQuery, Snowflake optimize CTEs similarly to subqueries.

  • Subqueries may be re-evaluated if the optimizer cannot guarantee reuse.

⚠️ Subqueries Can Have Performance Pitfalls

  • NOT IN with NULL produces wrong results unless carefully guarded.

  • Many engines struggle to optimize deeply nested subqueries.

  • Harder for the optimizer to “push down” predicates.

🎯 Best practice

Use subqueries only when they are the simplest expression of intent; otherwise use CTEs.


Types of Subqueries + Examples

1. IN Subqueries

These return a set of values for filtering.

Find customers who have placed orders

Find products in specific categories


2. NOT IN Subqueries (Be Careful!)

NOT IN ignores rows if the subquery returns NULL → often broken.

Find customers who never placed an order


3. Comparison Subqueries (ALL / ANY)

Employees who earn more than ANYONE in Marketing

Alternative using MAX()


4. EXISTS / NOT EXISTS (Most Efficient Filter Type)

EXISTS returns true as soon as one row matches—very efficient.

Basic EXISTS pattern

Find employees with no direct reports


5. Named Subqueries (Inline Views / Derived Tables)

You can name a subquery using AS to treat it like a temporary inline table.

Example

Another example using aggregation:


6. Nested Query Result Operators

Operator
Meaning

ALL

Expression must be true for every value in the subquery

ANY

Expression must be true for at least one value

IN

Equivalent to = ANY(subquery)

EXISTS

True if the subquery returns at least one row


7. OLAP / Analytics Subquery Patterns

Regions that performed above average


Above-average regions using EXISTS


Last updated