Skip to main content

Subqueries

A subquery is a query nested inside another query.

Subquery in WHERE

-- Employees earning above average
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- Employees in the 'Engineering' department
SELECT name
FROM employees
WHERE department_id = (
SELECT id FROM departments WHERE department_name = 'Engineering'
);

Subquery with IN

-- Employees in departments that have more than 10 people
SELECT name
FROM employees
WHERE department_id IN (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 10
);

Subquery in FROM (Derived Table)

-- Average of department averages
SELECT AVG(dept_avg) AS overall_avg
FROM (
SELECT department_id, AVG(salary) AS dept_avg
FROM employees
GROUP BY department_id
) AS dept_averages;

Subquery in SELECT

SELECT name, salary,
(SELECT AVG(salary) FROM employees) AS company_avg
FROM employees;

Correlated Subqueries

A correlated subquery references the outer query — it runs once per outer row.

-- Employees earning more than their department's average
SELECT name, salary, department_id
FROM employees e1
WHERE salary > (
SELECT AVG(salary) FROM employees e2
WHERE e2.department_id = e1.department_id
);

EXISTS & NOT EXISTS

Returns TRUE if the subquery returns any rows.

-- Departments that have at least one employee
SELECT department_name
FROM departments d
WHERE EXISTS (
SELECT 1 FROM employees e WHERE e.department_id = d.id
);

-- Departments with NO employees
SELECT department_name
FROM departments d
WHERE NOT EXISTS (
SELECT 1 FROM employees e WHERE e.department_id = d.id
);

Subquery Result Types

TypeReturnsExample Use
ScalarSingle valueWHERE salary > (SELECT AVG(salary) ...)
RowSingle rowWHERE (a, b) = (SELECT ...)
TableMultiple rows/columnsFROM (SELECT ...) AS t