Subqueries (also called inner queries or nested queries) are queries nested inside another SQL query. They allow you to break complex problems into smaller steps — for example, selecting rows based on aggregated values, checking existence, or computing derived values.
Basic forms:
-- Get customers who have placed at least one order
SELECT customer_id, name
FROM customers
WHERE id IN (
SELECT customer_id
FROM orders
);
-- Correlated subquery: mark employees whose salary > average salary in their department
SELECT e.id, e.name, e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(salary)
FROM employees
WHERE department_id = e.department_id
);
-- Use EXISTS to test for related rows (often faster for correlated checks)
SELECT p.id, p.title
FROM posts p
WHERE EXISTS (
SELECT 1
FROM comments c
WHERE c.post_id = p.id
);
-- Derived table (subquery in FROM) to compute totals per customer, then join
SELECT t.customer_id, t.total_orders
FROM (
SELECT customer_id, COUNT(*) AS total_orders
FROM orders
GROUP BY customer_id
) AS t
WHERE t.total_orders > 5;
-- Insert results of a query into another table
INSERT INTO vip_customers (customer_id, name)
SELECT id, name
FROM customers
WHERE id IN (
SELECT customer_id
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > 10
);
The IN (subquery) example returns all customers whose id appears in the list of customer IDs from orders. The correlated example calculates the department average per row and compares each employee's salary to that average. Use EXISTS when you only need to check presence — the subquery can often short-circuit.
EXISTS for correlated checks that only require presence.SELECT, ensure they return a single value per row (or use aggregation).orders.customer_id).