Discover how a simple join can save you hours of tedious searching and errors!
Why LATERAL join for correlated subqueries in PostgreSQL? - Purpose & Use Cases
Imagine you have two lists: one of customers and one of their orders. You want to find the latest order for each customer. Doing this by hand means checking each customer, then searching through all orders to find the newest one. This is like flipping through a huge stack of papers for every single person.
Manually comparing each customer to all orders is slow and tiring. It's easy to make mistakes, miss some orders, or get confused by the data. Doing this repeatedly wastes time and can cause errors, especially when the data grows large.
The LATERAL join lets the database do this smartly. It runs a small search for each customer to find their latest order, linking the two lists smoothly. This means you get accurate results quickly without messy manual checks.
SELECT customers.id, (SELECT order_date FROM orders WHERE orders.customer_id = customers.id ORDER BY order_date DESC LIMIT 1) FROM customers;SELECT customers.id, latest_orders.order_date FROM customers CROSS JOIN LATERAL (SELECT order_date FROM orders WHERE orders.customer_id = customers.id ORDER BY order_date DESC LIMIT 1) AS latest_orders;It enables fast, clear queries that find related data for each row without complicated or slow manual searching.
A store manager wants to see each customer's most recent purchase date to send personalized offers. Using LATERAL join, the manager gets this info instantly for thousands of customers.
Manual searching through related data is slow and error-prone.
LATERAL join lets the database efficiently find related rows per item.
This makes queries faster, clearer, and easier to write.
Practice
LATERAL join in PostgreSQL?Solution
Step 1: Understand what LATERAL join does
A LATERAL join allows a subquery to use columns from the current row of the main query.Step 2: Identify the main purpose
This means the subquery runs once per row, using that row's data to produce related results.Final Answer:
To run a subquery for each row of the main table using that row's data -> Option AQuick Check:
LATERAL join = per-row subquery execution [OK]
- Thinking LATERAL joins all rows at once
- Confusing LATERAL with regular JOIN
- Assuming LATERAL speeds up queries by caching
Solution
Step 1: Identify correct LATERAL syntax
LATERAL must be explicitly stated before the subquery or table function to allow referencing outer query columns.Step 2: Check each option
SELECT a.id, b.value FROM table_a a JOIN LATERAL (SELECT value FROM table_b WHERE b.a_id = a.id) b ON true; correctly uses JOIN LATERAL with a subquery referencing outer alias 'a'. SELECT a.id, b.value FROM table_a a JOIN (SELECT value FROM table_b WHERE b.a_id = a.id) b ON true; misses LATERAL keyword. SELECT a.id, b.value FROM table_a a LEFT JOIN LATERAL table_b b ON b.a_id = a.id; uses LATERAL but tries to join a table directly without subquery syntax. SELECT a.id, b.value FROM table_a a CROSS JOIN table_b b WHERE b.a_id = a.id; uses CROSS JOIN without LATERAL, so no correlation.Final Answer:
SELECT a.id, b.value FROM table_a a JOIN LATERAL (SELECT value FROM table_b WHERE b.a_id = a.id) b ON true; -> Option BQuick Check:
Correct LATERAL syntax includes keyword before subquery [OK]
- Omitting LATERAL keyword before subquery
- Using regular JOIN without correlation
- Trying to join tables directly without subquery
users(id, name)orders(id, user_id, amount)What will this query return?
SELECT u.name, o.amount FROM users u JOIN LATERAL (SELECT amount FROM orders WHERE user_id = u.id ORDER BY amount DESC LIMIT 1) o ON true;
Solution
Step 1: Understand the LATERAL subquery
The subquery selects the highest order amount per user by ordering descending and limiting to 1.Step 2: Analyze the JOIN LATERAL effect
For each user row, the subquery runs and returns that user's top order amount, joining on true to include all users with orders.Final Answer:
Each user with their highest order amount -> Option DQuick Check:
LATERAL subquery returns top order per user [OK]
- Thinking it returns all orders per user
- Assuming syntax error due to ON true
- Confusing join with CROSS JOIN
SELECT u.name, o.amount FROM users u JOIN LATERAL (SELECT amount FROM orders WHERE user_id = u.id ORDER BY amount DESC LIMIT 1) o;
Solution
Step 1: Check JOIN syntax
Every JOIN requires an ON clause or USING clause to specify join condition.Step 2: Verify the query
The query uses JOIN LATERAL but omits ON clause, causing syntax error.Final Answer:
Missing ON clause after LATERAL join -> Option CQuick Check:
JOIN must have ON or USING clause [OK]
- Forgetting ON clause after JOIN LATERAL
- Thinking subquery can't use outer columns
- Believing ORDER BY is disallowed in subqueries
Solution
Step 1: Understand the requirement
We want two most recent orders per customer, so order by order_date DESC and limit 2 in subquery.Step 2: Check each option
SELECT c.name, o.order_id FROM customers c JOIN LATERAL (SELECT order_id FROM orders WHERE customer_id = c.id ORDER BY order_date DESC LIMIT 2) o ON true; uses JOIN LATERAL with correct ordering and limit, joining on true to include all customers with orders. SELECT c.name, o.order_id FROM customers c JOIN orders o ON o.customer_id = c.id ORDER BY o.order_date DESC LIMIT 2; limits total rows, not per customer. SELECT c.name, o.order_id FROM customers c CROSS JOIN LATERAL orders o WHERE o.customer_id = c.id LIMIT 2; uses CROSS JOIN LATERAL incorrectly without subquery. SELECT c.name, o.order_id FROM customers c LEFT JOIN LATERAL (SELECT order_id FROM orders WHERE customer_id = c.id ORDER BY order_date ASC LIMIT 2) o ON true; orders ASC, which gives oldest orders, not recent.Final Answer:
SELECT c.name, o.order_id FROM customers c JOIN LATERAL (SELECT order_id FROM orders WHERE customer_id = c.id ORDER BY order_date DESC LIMIT 2) o ON true; -> Option AQuick Check:
LATERAL with ORDER BY DESC and LIMIT 2 per customer [OK]
- Limiting total rows instead of per customer
- Ordering ascending instead of descending
- Using CROSS JOIN LATERAL without subquery
Ready to prove it?
Pass the test and this pattern moves unknown
