Practice Questions — Self Joins and Multi-Table Queries
← Back to NotesTopic-Specific Questions
Question 1
Easy
Given the employees table with 7 rows, how many rows does this return?
SELECT e.name, m.name
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;LEFT JOIN keeps every employee. CEO has NULL manager.
7 rowsQuestion 2
Easy
How many rows does this return given the same employees table?
SELECT e.name, m.name
FROM employees e
JOIN employees m ON e.manager_id = m.id;INNER JOIN drops rows with NULL manager_id.
6 rowsQuestion 3
Easy
Which employee earns more than their manager?
Sample data: Divya (190k) reports to Rahul (180k).
Divya Nair (190000) - Rahul Verma (180000)Question 4
Easy
How many direct reports does Ananya (CEO) have?
Count employees where manager_id = 1.
2 (Rahul Verma, Sneha Kapoor)Question 5
Easy
How many tables are joined in this query?
SELECT c.name, p.name
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;Count the tables in FROM and JOIN.
4 tables (customers, orders, order_items, products)Question 6
Easy
True or False: A self join requires at least two different aliases for the same table.
Otherwise columns are ambiguous.
TrueQuestion 7
Easy
What is the problem with this old-style join?
SELECT c.name, o.id
FROM customers c, orders o
WHERE c.id = o.customer_id;Modern style vs implicit style.
It works but is discouraged. Forgetting the WHERE creates a cartesian product. Modern style: FROM customers c JOIN orders o ON c.id = o.customer_id.Question 8
Medium
What does this query return on the sample customers/orders/order_items data?
SELECT c.name, SUM(oi.qty * oi.price) AS total
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
GROUP BY c.id, c.name;Sum line totals per customer.
Aarav Kumar: 56000.00, Priya Sharma: 1000.00Question 9
Medium
What does this self-join query produce?
SELECT e.name
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE m.name = 'Sneha Kapoor';Employees whose manager is Sneha.
Karthik Raja, Pooja MenonQuestion 10
Medium
What does this query count?
SELECT m.name, COUNT(e.id) AS reports
FROM employees m
LEFT JOIN employees e ON e.manager_id = m.id
GROUP BY m.id, m.name;LEFT JOIN on the 'manager side'.
Number of direct reports per employee (0 if none).Question 11
Medium
Why does this return 0 rows instead of the CEO?
SELECT e.name
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.name = 'Ananya Reddy';CEO has NULL manager_id.
Ananya's manager_id is NULL, so the INNER JOIN finds no match and drops her row.Question 12
Medium
What does this query do?
SELECT e1.name, e2.name
FROM employees e1
JOIN employees e2
ON e1.department = e2.department
AND e1.id <> e2.id;Same department, different people.
Every ordered pair of co-workers in the same department. Includes both (A,B) and (B,A).Question 13
Medium
How many rows does this return for the sample employees table?
SELECT e1.name, e2.name
FROM employees e1
JOIN employees e2
ON e1.department = e2.department
AND e1.id < e2.id;3 Engineering + 3 Marketing + 1 CEO (alone). Pairs = C(3,2) + C(3,2) + 0.
6 rowsQuestion 14
Hard
What does this three-level self join return?
SELECT e.name, gm.name AS grandmanager
FROM employees e
JOIN employees m ON e.manager_id = m.id
JOIN employees gm ON m.manager_id = gm.id;Employee -> manager -> grandmanager. INNER JOIN requires all three.
Only employees at depth >= 2 with their grandmanager. Arjun -> Rahul -> Ananya, Divya -> Rahul -> Ananya, Karthik -> Sneha -> Ananya, Pooja -> Sneha -> Ananya.Question 15
Hard
What is returned by this query given our sample tables?
SELECT c.name, p.category, SUM(oi.qty * oi.price) AS cat_total
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
GROUP BY c.id, c.name, p.category;Group by customer and category.
Aarav / Electronics: 56000, Priya / Stationery: 1000Mixed & Application Questions
Question 1
Easy
What is a self join?
A table joined with...
A JOIN where a table is joined with itself using two different aliases. Used for hierarchical or same-table relationships like employee-manager.Question 2
Easy
Why should you prefer LEFT JOIN over INNER JOIN for 'list all employees with their manager'?
Top of hierarchy.
To include employees whose manager_id is NULL (like the CEO). INNER JOIN would drop them.Question 3
Easy
What is the problem with NATURAL JOIN?
Silent behavior when schema changes.
It silently joins on every same-named column. Adding a new column (like created_at) in both tables changes the join conditions unexpectedly.Question 4
Easy
Does join order affect the final result for INNER JOINs?
Associative property.
No. INNER JOINs are associative — (A JOIN B) JOIN C equals A JOIN (B JOIN C). Only performance may differ.Question 5
Easy
Rewrite this as an explicit join:
SELECT * FROM a, b WHERE a.id = b.a_id;Use JOIN ... ON.
SELECT * FROM a JOIN b ON a.id = b.a_id;Question 6
Medium
Write a query to find all employees managed by Sneha (directly or indirectly, up to 1 level deep).
Sneha has direct reports only.
SELECT e.name
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE m.name = 'Sneha Kapoor';Question 7
Medium
Given customers, orders, and order_items, write a query to find total orders and total revenue per customer.
DISTINCT count of orders + SUM of line totals.
SELECT c.name, COUNT(DISTINCT o.id) AS orders,
SUM(oi.qty * oi.price) AS revenue
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
GROUP BY c.id, c.name;Question 8
Medium
Given the sample data, what is Aarav's total revenue?
Order 101: 1 laptop @ 55000 + 2 mice @ 500.
56000Question 9
Medium
Why does a multi-table JOIN sometimes count rows incorrectly?
Row duplication from joining one-to-many relationships.
Because joining parents to children duplicates parent rows (one per child). Aggregations must use DISTINCT or GROUP BY correctly. COUNT(c.id) over a customer-orders-items join counts items, not customers.Question 10
Medium
When does a self join become insufficient and you need a recursive CTE?
Think about hierarchy depth.
When the depth of the hierarchy is unknown or variable. A self join handles exactly N levels by writing N-1 joins. A recursive CTE handles arbitrary depth in a single expression.Question 11
Hard
Write a query to find pairs of employees in the same department where one earns significantly more than the other (at least 50k difference).
Self join on department + salary difference condition.
SELECT e1.name AS high_earner, e2.name AS low_earner,
e1.department, e1.salary - e2.salary AS diff
FROM employees e1
JOIN employees e2
ON e1.department = e2.department
AND e1.salary >= e2.salary + 50000;Question 12
Hard
Write a query that lists each product along with total units sold and which customers bought it.
Four-table join + GROUP_CONCAT (MySQL) or aggregation.
SELECT p.name,
SUM(oi.qty) AS units,
GROUP_CONCAT(DISTINCT c.name ORDER BY c.name) AS buyers
FROM products p
LEFT JOIN order_items oi ON p.id = oi.product_id
LEFT JOIN orders o ON oi.order_id = o.id
LEFT JOIN customers c ON o.customer_id = c.id
GROUP BY p.id, p.name;Multiple Choice Questions
MCQ 1
What is a self join?
Answer: B
B is correct. Self join uses two aliases of the same table to represent two roles of the same entity (like employee and manager).
B is correct. Self join uses two aliases of the same table to represent two roles of the same entity (like employee and manager).
MCQ 2
Why must you alias the table in a self join?
Answer: B
B is correct. Without distinct aliases, MySQL cannot tell which instance of the table a column refers to, producing the error 'Not unique table/alias'.
B is correct. Without distinct aliases, MySQL cannot tell which instance of the table a column refers to, producing the error 'Not unique table/alias'.
MCQ 3
Which JOIN type should you use to list all employees with their manager, INCLUDING the CEO?
Answer: B
B is correct. The CEO has manager_id = NULL. LEFT JOIN keeps every employee and shows NULL for the CEO's manager. INNER JOIN would drop the CEO.
B is correct. The CEO has manager_id = NULL. LEFT JOIN keeps every employee and shows NULL for the CEO's manager. INNER JOIN would drop the CEO.
MCQ 4
How do JOINs compose with 3 tables?
Answer: B
B is correct. JOINs are naturally chainable. Each additional JOIN brings in one more table with its own ON condition, all in the same query.
B is correct. JOINs are naturally chainable. Each additional JOIN brings in one more table with its own ON condition, all in the same query.
MCQ 5
Is implicit join (FROM a, b WHERE ...) equivalent to INNER JOIN?
Answer: A
A is correct. When the WHERE supplies the matching condition, the result equals INNER JOIN. But explicit JOIN ... ON is preferred for clarity and safety.
A is correct. When the WHERE supplies the matching condition, the result equals INNER JOIN. But explicit JOIN ... ON is preferred for clarity and safety.
MCQ 6
Why is NATURAL JOIN risky?
Answer: B
B is correct. Adding a column with a common name (like created_at) to both tables silently adds a new join condition. The query may return different results without any obvious change.
B is correct. Adding a column with a common name (like created_at) to both tables silently adds a new join condition. The query may return different results without any obvious change.
MCQ 7
What does this query find?
SELECT e.name FROM employees e JOIN employees m ON e.manager_id = m.id WHERE e.salary > m.salary;Answer: B
B is correct.
B is correct.
e is the employee, m is the manager. The WHERE filters for employees whose salary exceeds their manager's.MCQ 8
How do you get unique unordered pairs in a self join without duplicates?
Answer: C
C is correct.
C is correct.
e1.id < e2.id eliminates both self-pairs and the reverse duplicate (A,B) vs (B,A).MCQ 9
In a customers -> orders -> order_items join, what would COUNT(*) return?
Answer: C
C is correct. The finest-grain table drives the row count after JOINs. COUNT(*) counts order items. Use COUNT(DISTINCT c.id) for customers, COUNT(DISTINCT o.id) for orders.
C is correct. The finest-grain table drives the row count after JOINs. COUNT(*) counts order items. Use COUNT(DISTINCT c.id) for customers, COUNT(DISTINCT o.id) for orders.
MCQ 10
Which statement about JOIN order is TRUE?
Answer: B
B is correct. INNER JOINs are associative and commutative. The optimizer may choose a different execution plan, affecting speed. For readability, write JOINs in the order you naturally think about the relationships.
B is correct. INNER JOINs are associative and commutative. The optimizer may choose a different execution plan, affecting speed. For readability, write JOINs in the order you naturally think about the relationships.
MCQ 11
What does this produce?
SELECT m.name, COUNT(e.id) AS n FROM employees m LEFT JOIN employees e ON e.manager_id = m.id GROUP BY m.id, m.name;Answer: B
B is correct. LEFT JOIN + COUNT on the 'reports side' gives zero for individual contributors. Every employee is treated as a potential manager.
B is correct. LEFT JOIN + COUNT on the 'reports side' gives zero for individual contributors. Every employee is treated as a potential manager.
MCQ 12
A query joins 4 tables with 100 rows each. One JOIN condition is missing. How many rows could the result have?
Answer: C
C is correct. A missing JOIN condition on one table produces a partial cartesian: 100 * 100 * 100 * 100 = 100 million rows. This is why multi-table queries must be sanity-checked during development.
C is correct. A missing JOIN condition on one table produces a partial cartesian: 100 * 100 * 100 * 100 = 100 million rows. This is why multi-table queries must be sanity-checked during development.
MCQ 13
When would you choose a recursive CTE over a self join?
Answer: B
B is correct. Self join handles a known, fixed depth with N-1 joins. Recursive CTEs handle arbitrary depth. For 'find all ancestors' or 'all descendants', use recursive CTEs.
B is correct. Self join handles a known, fixed depth with N-1 joins. Recursive CTEs handle arbitrary depth. For 'find all ancestors' or 'all descendants', use recursive CTEs.
MCQ 14
What is wrong with NATURAL JOIN in production code?
Answer: B
B is correct. Adding a column with a common name (e.g., created_at, updated_at) to both tables changes what NATURAL JOIN matches on — silently. Queries that worked yesterday return different results today. Always use explicit ON.
B is correct. Adding a column with a common name (e.g., created_at, updated_at) to both tables changes what NATURAL JOIN matches on — silently. Queries that worked yesterday return different results today. Always use explicit ON.
Coding Challenges
Challenge 1: Employees with Their Manager Name
EasyWrite a query that lists every employee with their manager's name. Include the CEO with NULL manager.
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id
ORDER BY e.id;Challenge 2: Employees Earning More Than Their Manager
EasyFind all employees whose salary exceeds their manager's salary.
SELECT e.name AS employee, e.salary, m.name AS manager, m.salary AS mgr_salary
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.salary > m.salary;Challenge 3: Count Direct Reports Per Manager
MediumFor each employee, show the number of direct reports (0 for individual contributors).
SELECT m.name AS manager, COUNT(e.id) AS reports
FROM employees m
LEFT JOIN employees e ON e.manager_id = m.id
GROUP BY m.id, m.name
ORDER BY reports DESC;Challenge 4: Total Revenue Per Customer (3-Table Join)
MediumCalculate total revenue per customer using customers, orders, and order_items.
SELECT c.name, SUM(oi.qty * oi.price) AS revenue
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
GROUP BY c.id, c.name
ORDER BY revenue DESC;Challenge 5: Pairs of Employees in Same Department
MediumList all unique pairs of employees who work in the same department. No self-pairs, no duplicates.
SELECT e1.name AS emp1, e2.name AS emp2, e1.department
FROM employees e1
JOIN employees e2
ON e1.department = e2.department
AND e1.id < e2.id
ORDER BY e1.department, e1.id;Challenge 6: Top-Selling Product Category
HardUsing all 4 tables (customers, orders, order_items, products), find the product category with the highest total revenue.
SELECT p.category, SUM(oi.qty * oi.price) AS revenue
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
GROUP BY p.category
ORDER BY revenue DESC
LIMIT 1;Challenge 7: Employee, Manager, Grandmanager Chain
HardFor each employee, show their manager and their manager's manager (grandmanager). Include all employees, even those at the top.
SELECT e.name AS employee,
m.name AS manager,
gm.name AS grandmanager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id
LEFT JOIN employees gm ON m.manager_id = gm.id
ORDER BY e.id;Challenge 8: Customers Who Have Never Ordered Electronics
HardFind customers who have placed orders but never bought anything in the 'Electronics' category.
SELECT DISTINCT c.name
FROM customers c
JOIN orders o ON c.id = o.customer_id
WHERE NOT EXISTS (
SELECT 1
FROM order_items oi
JOIN products p ON oi.product_id = p.id
WHERE oi.order_id = o.id AND p.category = 'Electronics'
);Need to Review the Concepts?
Go back to the detailed notes for this chapter.
Read Chapter NotesWant to master SQL and databases with a mentor?
Explore our MySQL Masterclass