SELECT o.order_id, s.status
FROM orders o
JOIN shipments s
ON s.order_id = o.order_id
AND s.status = 'delivered';Predicates in the ON clause affect join matching behavior.
Advanced relational query patterns for joins, subqueries, EXISTS, IN, set operations, and correlated queries.
Practical join patterns with predicates.
SELECT o.order_id, s.status
FROM orders o
JOIN shipments s
ON s.order_id = o.order_id
AND s.status = 'delivered';Predicates in the ON clause affect join matching behavior.
SELECT c.customer_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL;This is a common anti-join pattern.
SELECT c.customer_id, x.total_spent
FROM customers c
JOIN (
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
) x ON x.customer_id = c.customer_id;This pattern keeps the outer query simpler when joining summarized data.
Nested query patterns.
SELECT *
FROM products
WHERE category_id IN (
SELECT category_id
FROM categories
WHERE is_active = TRUE
);Subqueries are useful when one query determines the filter set for another.
SELECT employee_id, salary,
(SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;A scalar subquery must return at most one row.
SELECT e.employee_id, e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department_id = e.department_id
);Correlated subqueries execute relative to each outer row.
SELECT q.department_id, q.avg_salary
FROM (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
) q;Derived tables let you treat nested query results as temporary relations.
Semi-joins, anti-joins, and unions.
SELECT c.customer_id
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);EXISTS is often efficient for existence checks.
SELECT c.customer_id
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);NOT EXISTS is a robust anti-join approach.
SELECT email FROM customers
UNION
SELECT email FROM leads;UNION removes duplicates. Use UNION ALL to preserve them.
SELECT event_type FROM web_events
UNION ALL
SELECT event_type FROM mobile_events;UNION ALL is usually faster than UNION because it skips duplicate elimination.
SELECT user_id FROM newsletter_subscribers
INTERSECT
SELECT user_id FROM paying_customers;INTERSECT behaves like set intersection in SQL dialects that support it.
SELECT user_id FROM all_users
EXCEPT
SELECT user_id FROM banned_users;Some dialects use MINUS instead of EXCEPT.