ποΈ SQL Β· Topic 13 of 20
Advanced Joins β SQL Questions with Answers
30 practice questions on Advanced Joins, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
1 easy Β· 14 medium Β· 15 hard Β· Part of SQL: Databases from basics to window functions - 20 topics.
Medium questions (14)
Q1. medium
What is a SELF JOIN?
SELECT e.name AS employee, m.name AS manager
FROM employees e
JOIN employees m ON e.manager_id = m.id;
- A Joining a table to ITSELF using two aliases
- B A join that repeats automatically
- C A join with no condition
- D A join between two databases
Answer: A β Joining a table to ITSELF using two aliases
The same table appears twice under different aliases, letting you relate rows within one table - such as employees to their managers.
Self joinHierarchies
Q2. medium
Why are aliases mandatory in a self join?
- A Both sides are the same table, so aliases distinguish the two roles and remove ambiguity
- B For speed
- C To sort the rows
- D They are optional
Answer: A β Both sides are the same table, so aliases distinguish the two roles and remove ambiguity
Without aliases like e and m, the database cannot tell which 'name' or 'id' you mean. Aliases give each copy of the table a distinct identity.
Self joinAliases
Q5. medium
When is a CROSS JOIN genuinely useful?
- A Generating all combinations - e.g. a calendar of every date x every store, or product variants
- B It is never useful
- C For filtering rows
- D For sorting
Answer: A β Generating all combinations - e.g. a calendar of every date x every store, or product variants
Deliberate CROSS JOINs build complete grids: all days for all stores to plot sales (filling gaps with zeros), or all size/colour combinations for inventory.
CROSS JOINCombinations
Q8. medium
How do you join four tables in one query?
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items i ON i.order_id = o.id
JOIN products p ON p.id = i.product_id
- A Chain the JOINs, each with its own ON condition following the relationships
- B Use four FROM clauses
- C You cannot join four tables
- D Use four subqueries
Answer: A β Chain the JOINs, each with its own ON condition following the relationships
Multi-table joins are routine in reporting. Follow the foreign keys: orders to customers, orders to items, items to products.
Multi-table joins
Q10. medium
How do you compare each row to the previous row using a self join?
- A Join the table to itself ON b.id = a.id - 1 (or on a matching sequence)
- B It cannot be done
- C Use CROSS JOIN
- D Use GROUP BY
Answer: A β Join the table to itself ON b.id = a.id - 1 (or on a matching sequence)
Self joining on adjacent ids compares consecutive rows - though window functions (LAG/LEAD, topic 20) are the modern, more reliable tool for this.
Self joinLAGLEAD
Q13. medium
How do you find duplicate rows using a self join?
- A Join ON matching columns AND a.id <> b.id to find rows that share values
- B Use CROSS JOIN
- C Duplicates cannot be found
- D Use DISTINCT only
Answer: A β Join ON matching columns AND a.id <> b.id to find rows that share values
Rows with equal email but different id are duplicates. GROUP BY ... HAVING COUNT(*) > 1 is usually cleaner, but a self join can also list the offending pairs.
DuplicatesSelf join
Q15. medium
How does a self join model an org chart at one level?
- A Employee row joins to another employee row via manager_id = id
- B It joins two tables
- C It uses CROSS JOIN
- D It cannot
Answer: A β Employee row joins to another employee row via manager_id = id
Each employee stores their manager's id, which points back into the same table. One self join gives employee + manager; two levels need two joins or recursion.
Self joinOrg chart
Q17. medium
Can CROSS JOIN be combined with a WHERE clause?
- A Yes - and a CROSS JOIN plus a WHERE equality condition is effectively an INNER JOIN
- B No, CROSS JOIN forbids WHERE
- C Only with ON
- D It errors
Answer: A β Yes - and a CROSS JOIN plus a WHERE equality condition is effectively an INNER JOIN
FROM a CROSS JOIN b WHERE a.id = b.a_id filters the product down to matches - the old implicit-join style. Explicit INNER JOIN ON expresses the same intent more safely.
CROSS JOINWHERE
Q20. medium
How do you list every combination of two small lists?
- A CROSS JOIN the two tables
- B INNER JOIN with no ON
- C UNION them
- D GROUP BY both
Answer: A β CROSS JOIN the two tables
CROSS JOIN is the intended tool for building all combinations, such as a menu of every base x every topping.
CROSS JOINCombinations
Q22. medium
What does joining a lookup/reference table achieve?
- A It replaces stored codes with human-readable labels (e.g. status_id -> status name)
- B It speeds up writes
- C It deletes codes
- D Nothing
Answer: A β It replaces stored codes with human-readable labels (e.g. status_id -> status name)
Normalised designs store small codes and keep the labels in a lookup table. Joining brings back readable text: JOIN statuses s ON o.status_id = s.id.
Lookup tableNormalization
Q24. medium
How do you find employees who have the same manager as 'Ana'?
- A Self join on manager_id, matching Ana's manager to others
- B CROSS JOIN employees
- C GROUP BY manager
- D It cannot be done
Answer: A β Self join on manager_id, matching Ana's manager to others
Self join a (the person) to b (Ana) on a.manager_id = b.manager_id where b.name = 'Ana'. Peer-finding is a natural self-join task.
Self joinPeers
Q26. medium
What is a bridge (junction) table's role in joins?
- A It sits between two tables in a many-to-many relationship, joined to each side
- B It stores backups
- C It sorts data
- D It has no role
Answer: A β It sits between two tables in a many-to-many relationship, joined to each side
students <-> enrollments <-> courses: two joins through the bridge connect the many-to-many sides. The bridge often carries relationship data like a grade.
Junction tableMany-to-many
Q28. medium
How do you show a manager and ALL their direct reports?
- A Self join employees (report) to employees (manager) ON report.manager_id = manager.id
- B CROSS JOIN employees
- C GROUP BY manager only
- D It cannot be done
Answer: A β Self join employees (report) to employees (manager) ON report.manager_id = manager.id
One self join lists each direct report alongside their manager. Ordering by manager groups each team together.
Self joinReporting lines
Q30. medium
Which join type has no ON condition by design?
- A CROSS JOIN
- B INNER JOIN
- C LEFT JOIN
- D FULL JOIN
Answer: A β CROSS JOIN
CROSS JOIN deliberately pairs every combination and needs no matching condition. All other join types require an ON (or USING) clause.
CROSS JOINJoin types
Hard questions (15)
Q3. hard
How do you find pairs of employees in the SAME department (without duplicates)?
- A Self join ON a.dept = b.dept AND a.id < b.id
- B Self join ON a.dept = b.dept
- C INNER JOIN with GROUP BY
- D CROSS JOIN
Answer: A β Self join ON a.dept = b.dept AND a.id < b.id
The a.id < b.id condition prevents matching a row with itself and avoids listing each pair twice (A-B and B-A). A classic self-join interview question.
Self joinPairs
Q6. hard
What is an accidental Cartesian product, and how does it happen?
- A A huge result from a missing or wrong join condition - rows multiply instead of matching
- B A deliberate CROSS JOIN
- C A type of index
- D An empty result
Answer: A β A huge result from a missing or wrong join condition - rows multiply instead of matching
Forgetting ON (or a comma-join without WHERE) pairs every row with every row. Two 10,000-row tables produce 100 million rows - a common cause of runaway queries.
Cartesian productBugs
Q7. hard
How do you build a hierarchy of unlimited depth (e.g. org chart)?
- A A recursive CTE (WITH RECURSIVE) - a self join only reaches a fixed number of levels
- B Nested self joins forever
- C CROSS JOIN
- D It is impossible
Answer: A β A recursive CTE (WITH RECURSIVE) - a self join only reaches a fixed number of levels
Each self join adds exactly one level. For arbitrary depth (manager of manager of ...), a recursive CTE walks the tree. (CTEs are covered in topic 15.)
Recursive CTEHierarchies
Q9. hard
In a multi-table join, why can row counts balloon unexpectedly?
- A Each one-to-many join multiplies rows - joining orders to items AND to payments can multiply items by payments
- B Joins always reduce rows
- C It is a syntax error
- D Only with CROSS JOIN
Answer: A β Each one-to-many join multiplies rows - joining orders to items AND to payments can multiply items by payments
If an order has 3 items and 2 payments, joining both to the order yields 3 x 2 = 6 rows. Aggregate each branch separately (in subqueries) before combining to avoid inflated totals.
- A hard-to-spot cause of wrong sums in reports.
Fan-outMulti-table joins
Q11. hard
What does a self join reveal here?
SELECT a.name FROM employees a JOIN employees b ON a.salary < b.salary WHERE b.name = 'Ana';
- A Employees who earn LESS than Ana
- B Ana's manager
- C Employees earning more than Ana
- D An error
Answer: A β Employees who earn LESS than Ana
Self joins with inequality conditions compare rows against a reference row - here, everyone paid below Ana. Non-equi joins (using <, >, BETWEEN) are a powerful advanced technique.
Non-equi joinSelf join
Q12. hard
What is a non-equi join?
SELECT s.id, t.discount
FROM sales s JOIN tiers t ON s.amount BETWEEN t.min_amt AND t.max_amt;
- A A join whose condition uses something other than equality (<, >, BETWEEN)
- B A join with no condition
- C An invalid join
- D A join on two equal columns
Answer: A β A join whose condition uses something other than equality (<, >, BETWEEN)
For example joining sales to a tier table ON amount BETWEEN tier.low AND tier.high to assign a discount band. Equality is common but not required.
Non-equi joinRange join
Q14. hard
Why order multi-table joins to filter the largest table early?
- A Reducing rows early means later joins process fewer rows - though the optimiser often reorders automatically
- B Order never matters
- C It changes the result
- D To avoid syntax errors
Answer: A β Reducing rows early means later joins process fewer rows - though the optimiser often reorders automatically
For INNER joins the RESULT is order-independent, but applying selective filters early can help performance. Good indexes and current statistics matter more than manual ordering.
PerformanceOptimiser
Q16. hard
What does a LEFT self join achieve for the top of a hierarchy?
- A It keeps the CEO (whose manager_id is NULL) in the result with a NULL manager
- B It removes the CEO
- C It duplicates the CEO
- D Nothing
Answer: A β It keeps the CEO (whose manager_id is NULL) in the result with a NULL manager
An INNER self join would drop the top person because they have no manager to match. LEFT JOIN preserves them, showing NULL for the manager column.
LEFT JOINSelf join
Q18. hard
How do you generate a row for every date in a range (a date spine)?
-- PostgreSQL
SELECT d::date, COALESCE(SUM(s.amt),0)
FROM generate_series('2026-01-01','2026-01-31',INTERVAL '1 day') d
LEFT JOIN sales s ON s.day = d::date GROUP BY 1;
- A CROSS JOIN or a recursive CTE / generate_series to produce all dates, then LEFT JOIN the data
- B Data always has every date
- C GROUP BY date
- D It is impossible
Answer: A β CROSS JOIN or a recursive CTE / generate_series to produce all dates, then LEFT JOIN the data
Reports often need zero-filled gaps (days with no sales). Build a complete date spine, then LEFT JOIN the actual data so missing days show 0.
Date spinegenerate_series
Q19. hard
What does LATERAL / CROSS APPLY allow?
SELECT c.name, o.total
FROM customers c
CROSS JOIN LATERAL (
SELECT total FROM orders WHERE customer_id = c.id ORDER BY total DESC LIMIT 3
) o;
- A A subquery in the FROM clause that references columns from the preceding table - like a per-row lookup
- B Nothing new
- C A faster CROSS JOIN
- D Joining three tables
Answer: A β A subquery in the FROM clause that references columns from the preceding table - like a per-row lookup
LATERAL (PostgreSQL) and CROSS APPLY (SQL Server) let a join's right side depend on the left row - perfect for 'top 3 orders per customer'.
LATERALCROSS APPLY
Q21. hard
In a query joining orders, items and payments, how do you avoid inflated sums?
- A Aggregate items and payments in SEPARATE subqueries first, then join the summaries to orders
- B Use DISTINCT on everything
- C Join all three directly and SUM
- D Use CROSS JOIN
Answer: A β Aggregate items and payments in SEPARATE subqueries first, then join the summaries to orders
Joining two one-to-many branches multiplies rows. Pre-aggregating each branch to one row per order removes the fan-out before you combine them.
Fan-outSubqueriesAggregation
Q23. hard
What is the danger of SELECT * in a multi-table join?
- A Duplicate column names, huge unnecessary output, and fragile code if any table changes
- B It is always fine
- C It errors
- D It sorts the result
Answer: A β Duplicate column names, huge unnecessary output, and fragile code if any table changes
Several tables may each have an 'id' or 'name'. Selecting only the qualified columns you need avoids ambiguous output and reduces data transfer.
SELECT *Best practices
Q25. hard
How does an anti-join differ from a semi-join?
- A Semi-join keeps left rows that HAVE a match (EXISTS); anti-join keeps those that have NO match (NOT EXISTS)
- B They are the same
- C Semi-join duplicates rows
- D Anti-join is invalid
Answer: A β Semi-join keeps left rows that HAVE a match (EXISTS); anti-join keeps those that have NO match (NOT EXISTS)
EXISTS is a semi-join (existence test, no fan-out). NOT EXISTS or LEFT JOIN ... IS NULL is an anti-join. Both return left columns only, unlike a normal join.
Semi-joinAnti-joinEXISTS
Q27. hard
Why can a range self join (t.value BETWEEN a AND b) be slow?
- A Range conditions are harder to index than equality, often forcing more comparisons
- B It is always fast
- C Ranges are not allowed in joins
- D It errors
Answer: A β Range conditions are harder to index than equality, often forcing more comparisons
Equality joins can use hash/merge strategies efficiently; range joins often fall back to nested loops. Appropriate indexes and small tier tables keep them manageable.
Non-equi joinPerformance
Q29. hard
What is the safest way to verify a complex join is correct?
- A Check the row count and spot-check sample rows against expected relationships before trusting aggregates
- B Assume it is correct
- C Only run it in production
- D Add more joins
Answer: A β Check the row count and spot-check sample rows against expected relationships before trusting aggregates
Unexpected row counts reveal fan-out or Cartesian products. Verifying the grain (one row per what?) before aggregating prevents silently wrong reports.
TestingDebugging joins