🚀
11. Subqueries and CTEs
++++
Data Engineering
May 2026×10 min read

Use nested SELECT queries and WITH common table expressions to break complex MySQL logic into readable steps.

11. Subqueries and CTEs

Driptanil Datta
Driptanil DattaSoftware Developer

Subqueries and CTEs

Subqueries and CTEs let one query depend on the result of another query. They are useful when a problem is easier to solve in steps.

Scalar subquery

A scalar subquery returns one value.

SELECT
  order_id,
  total_amount
FROM orders
WHERE total_amount > (
  SELECT AVG(total_amount)
  FROM orders
);

This returns orders whose value is above the overall average.

IN subquery

Use an IN subquery when the inner query returns a list.

SELECT *
FROM customers
WHERE customer_id IN (
  SELECT customer_id
  FROM orders
  WHERE status = "paid"
);

This returns customers who have at least one paid order.

NOT IN and NULL caution

NOT IN can behave unexpectedly if the subquery returns NULL. A safer pattern is often NOT EXISTS.

SELECT *
FROM customers AS c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders AS o
  WHERE o.customer_id = c.customer_id
);

This returns customers with no matching orders.

Derived table

A derived table is a subquery in the FROM clause.

SELECT
  customer_id,
  paid_total
FROM (
  SELECT
    customer_id,
    SUM(total_amount) AS paid_total
  FROM orders
  WHERE status = "paid"
  GROUP BY customer_id
) AS customer_totals
WHERE paid_total >= 500;

CTE with WITH

A CTE names a temporary result set at the top of the query.

WITH customer_totals AS (
  SELECT
    customer_id,
    SUM(total_amount) AS paid_total
  FROM orders
  WHERE status = "paid"
  GROUP BY customer_id
)
SELECT
  customer_id,
  paid_total
FROM customer_totals
WHERE paid_total >= 500;

CTEs usually read better than deeply nested derived tables.

Multiple CTEs

WITH paid_orders AS (
  SELECT *
  FROM orders
  WHERE status = "paid"
),
customer_totals AS (
  SELECT
    customer_id,
    SUM(total_amount) AS paid_total
  FROM paid_orders
  GROUP BY customer_id
)
SELECT *
FROM customer_totals
ORDER BY paid_total DESC;

Use CTEs when each step has a clear meaning and you want the final query to tell a story.

Drip

Driptanil Datta

Software Developer

Building full-stack systems, one commit at a time. This blog is a centralized learning archive for developers.

Legal Notes
Disclaimer

The content provided on this blog is for educational and informational purposes only. While I strive for accuracy, all information is provided "as is" without any warranties of completeness, reliability, or accuracy. Any action you take upon the information found on this website is strictly at your own risk.

Copyright & IP

Certain technical content, interview questions, and datasets are curated from external educational sources to provide a centralized learning resource. Respect for original authorship is maintained; no copyright infringement is intended. All trademarks, logos, and brand names are the property of their respective owners.

System Operational

© 2026 Driptanil Datta. All rights reserved.