Bird
Raised Fist0
PostgreSQLquery~10 mins

LATERAL join for correlated subqueries in PostgreSQL - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - LATERAL join for correlated subqueries
Start with main table
↓
For each row in main table
↓
Run subquery using current row values
↓
Join subquery result with main row
↓
Repeat for all rows
↓
Return combined result set
The LATERAL join runs a subquery for each row of the main table, using that row's values inside the subquery, then joins the subquery result back to the main row.
Execution Sample
PostgreSQL
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN LATERAL (
  SELECT order_id
  FROM orders o
  WHERE o.customer_id = c.id
  LIMIT 1
) o ON true;
For each customer, find one order using a subquery that refers to the current customer row.
Execution Table
StepCurrent customer (c.id, c.name)Subquery executedSubquery result (order_id)Joined output row
1(1, 'Alice')SELECT order_id FROM orders WHERE customer_id=1 LIMIT 1101(Alice, 101)
2(2, 'Bob')SELECT order_id FROM orders WHERE customer_id=2 LIMIT 1201(Bob, 201)
3(3, 'Carol')SELECT order_id FROM orders WHERE customer_id=3 LIMIT 1NULL (no orders)(Carol, NULL)
4No more customersNo subqueryNo resultEnd of output
💡 All customers processed; subqueries run for each; output combined rows returned.
Variable Tracker
VariableStartAfter 1After 2After 3Final
c.idnone123end
c.namenoneAliceBobCarolend
subquery order_idnone101201NULLend
Key Moments - 2 Insights
Why does the subquery use the current row's customer id?
Because the LATERAL join lets the subquery access columns from the current main table row, so it can filter orders for that specific customer (see execution_table steps 1-3).
What happens if the subquery returns no rows for a customer?
The join still outputs the main row with NULLs for the subquery columns, as shown for Carol in step 3 of the execution_table.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the subquery result for customer Bob at step 2?
A201
B101
CNULL
DNo result
💡 Hint
Check the 'Subquery result (order_id)' column at step 2 in the execution_table.
At which step does the subquery return no orders?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Look for 'NULL (no orders)' in the 'Subquery result' column in the execution_table.
If the subquery did not use LATERAL, what would happen?
AIt would run faster
BIt could not refer to the current customer row's id
CIt would return all orders for all customers
DIt would return no rows
💡 Hint
LATERAL allows the subquery to access columns from the main query's current row (see concept_flow).
Concept Snapshot
LATERAL join lets a subquery use columns from each row of the main table.
Syntax: FROM main_table LEFT JOIN LATERAL (subquery referencing main_table) ON condition.
Runs subquery once per main row, joining results.
Useful for correlated subqueries returning multiple columns.
If subquery returns no rows, main row still appears with NULLs.
Full Transcript
The LATERAL join in PostgreSQL runs a subquery for each row of the main table. This subquery can use values from the current row, making it a correlated subquery. For example, for each customer, the subquery finds one order belonging to that customer. The execution table shows each customer row, the subquery run with that customer's id, the order found (or NULL if none), and the combined output row. If the subquery returns no rows, the main row still appears with NULLs for the subquery columns. This is because LATERAL allows the subquery to access the current row's columns. Without LATERAL, the subquery could not refer to the main table's current row, so it would not filter orders per customer. This technique is useful to join each row with related data computed on the fly.

Practice

(1/5)
1. What is the main purpose of using a LATERAL join in PostgreSQL?
easy
A. To run a subquery for each row of the main table using that row's data
B. To join two tables without any condition
C. To create a temporary table for all rows at once
D. To speed up queries by caching results

Solution

  1. Step 1: Understand what LATERAL join does

    A LATERAL join allows a subquery to use columns from the current row of the main query.
  2. Step 2: Identify the main purpose

    This means the subquery runs once per row, using that row's data to produce related results.
  3. Final Answer:

    To run a subquery for each row of the main table using that row's data -> Option A
  4. Quick Check:

    LATERAL join = per-row subquery execution [OK]
Hint: LATERAL runs subqueries per row using that row's data [OK]
Common Mistakes:
  • Thinking LATERAL joins all rows at once
  • Confusing LATERAL with regular JOIN
  • Assuming LATERAL speeds up queries by caching
2. Which of the following is the correct syntax to use a LATERAL join in PostgreSQL?
easy
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;
B. 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;
C. SELECT a.id, b.value FROM table_a a LEFT JOIN LATERAL table_b b ON b.a_id = a.id;
D. SELECT a.id, b.value FROM table_a a CROSS JOIN table_b b WHERE b.a_id = a.id;

Solution

  1. Step 1: Identify correct LATERAL syntax

    LATERAL must be explicitly stated before the subquery or table function to allow referencing outer query columns.
  2. 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.
  3. 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 B
  4. Quick Check:

    Correct LATERAL syntax includes keyword before subquery [OK]
Hint: LATERAL keyword must precede subquery to access outer columns [OK]
Common Mistakes:
  • Omitting LATERAL keyword before subquery
  • Using regular JOIN without correlation
  • Trying to join tables directly without subquery
3. Given the tables:
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;
medium
A. Users with all their orders listed
B. All orders with user names repeated
C. Syntax error due to missing ON condition
D. Each user with their highest order amount

Solution

  1. Step 1: Understand the LATERAL subquery

    The subquery selects the highest order amount per user by ordering descending and limiting to 1.
  2. 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.
  3. Final Answer:

    Each user with their highest order amount -> Option D
  4. Quick Check:

    LATERAL subquery returns top order per user [OK]
Hint: LATERAL runs subquery per user to get top order [OK]
Common Mistakes:
  • Thinking it returns all orders per user
  • Assuming syntax error due to ON true
  • Confusing join with CROSS JOIN
4. Identify the error in this query:
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;
medium
A. Subquery cannot reference outer query columns
B. Incorrect alias usage for orders table
C. Missing ON clause after LATERAL join
D. ORDER BY not allowed in subqueries

Solution

  1. Step 1: Check JOIN syntax

    Every JOIN requires an ON clause or USING clause to specify join condition.
  2. Step 2: Verify the query

    The query uses JOIN LATERAL but omits ON clause, causing syntax error.
  3. Final Answer:

    Missing ON clause after LATERAL join -> Option C
  4. Quick Check:

    JOIN must have ON or USING clause [OK]
Hint: Always add ON clause after JOIN LATERAL [OK]
Common Mistakes:
  • Forgetting ON clause after JOIN LATERAL
  • Thinking subquery can't use outer columns
  • Believing ORDER BY is disallowed in subqueries
5. You want to list each customer with their two most recent orders using LATERAL join. Which query correctly achieves this?
hard
A. 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;
B. 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;
C. SELECT c.name, o.order_id FROM customers c CROSS JOIN LATERAL orders o WHERE o.customer_id = c.id LIMIT 2;
D. 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;

Solution

  1. Step 1: Understand the requirement

    We want two most recent orders per customer, so order by order_date DESC and limit 2 in subquery.
  2. 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.
  3. 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 A
  4. Quick Check:

    LATERAL with ORDER BY DESC and LIMIT 2 per customer [OK]
Hint: Use LATERAL with ORDER BY DESC and LIMIT for top N per row [OK]
Common Mistakes:
  • Limiting total rows instead of per customer
  • Ordering ascending instead of descending
  • Using CROSS JOIN LATERAL without subquery
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard