A subquery is a nested SELECT that supplies data to an outer query for filtering, aggregation, or data transformation.
A subquery is a SELECT statement enclosed in parentheses that returns a result set consumed by the outer query. You can place it in SELECT, FROM, WHERE, or HAVING clauses to compute values, filter rows, or build derived tables.
Use a subquery when the nested logic is easier to read, when you need aggregate results in a single column, or when the outer query depends on the result of the inner query. Use JOINs for set-based combination of rows to avoid unnecessary nesting.
Enclose the inner SELECT in parentheses. It may be correlated (referencing outer columns) or uncorrelated. Place it where a value list, table, or scalar expression is expected.
-- In WHERE
SELECT *
FROM Orders o
WHERE o.customer_id IN (SELECT id FROM Customers WHERE created_at > now() - interval '30 days');
-- In FROM (derived table)
SELECT s.customer_id, s.recent_total
FROM (
SELECT customer_id, SUM(total_amount) AS recent_total
FROM Orders
WHERE order_date > now() - interval '30 days'
GROUP BY customer_id
) AS s;
-- Scalar subquery in SELECT
SELECT id,
(SELECT COUNT(*) FROM OrderItems oi WHERE oi.order_id = o.id) AS item_cnt
FROM Orders o;
Use IN, EXISTS, =, <>, >=, or < operators. EXISTS is fastest when the inner query only needs to check existence.
SELECT *
FROM Products p
WHERE EXISTS (
SELECT 1 FROM OrderItems oi WHERE oi.product_id = p.id AND oi.quantity > 5
);
Return a single value to enrich each row. Ensure the subquery returns at most one row or use aggregation to avoid errors.
Yes. Use a subquery to compute the filter set or new values.
UPDATE Products p
SET stock = stock - s.qty
FROM (
SELECT product_id, SUM(quantity) AS qty
FROM OrderItems
GROUP BY product_id
) AS s
WHERE p.id = s.product_id;
1) Prefer EXISTS over IN for correlated checks. 2) Index columns referenced in subqueries. 3) Alias derived tables clearly. 4) Validate that scalar subqueries return one row.
Misusing subqueries where JOINs are simpler, or forgetting to correlate inner queries leading to cartesian results.
Not necessarily. PostgreSQL can transform some subqueries into joins internally. Performance depends on indexes, data volume, and whether the subquery is correlated.
Yes, you can nest subqueries to any depth, but readability and performance suffer. Break complex logic into CTEs or temp tables when nesting becomes confusing.
Use a common table expression when the same subquery result is reused, when you need recursion, or when you want to improve code clarity.