Practice combining related tables with INNER JOIN and LEFT JOIN exercises. These 40 interactive challenges use real schemas and instant query validation.
Start with a free exercise
Employee Department NamesMore exercises on this topicConcept guide
SQL JOINs combine rows from related tables. INNER JOIN keeps matching rows, while LEFT JOIN preserves every row from the left table and fills missing matches with NULL.
INNER JOIN returns only matching rows. LEFT JOIN returns every row from the left table and matching rows from the right table, using NULL when no match exists.
List each employee's full name alongside their department name. Use INNER JOIN. Return columns: first_name, last_name, department_name.
Find all customers who have never placed an order. Return columns: id, name, email.
Calculate total revenue (sum of total_amount) per customer, showing customer name and total revenue, sorted by revenue descending. Return columns: customer_name, total_revenue. Order results by: total_revenue DESC.
For each product, show the total quantity sold and total revenue from order_items. Include product name. Return columns: product_name, total_quantity, total_revenue. Order results by: total_revenue DESC.
Show each department name, employee count, and total payroll. Return columns: department_name, employee_count, total_payroll. Order results by: d.id.
Show all departments and their employee count, including departments with no employees. Return columns: department_name, employee_count. Order results by: d.id.
Show every product and its revenue, using zero when it has no sales. Return columns: product_name, revenue. Order results by: p.id.
List each managed employee together with their manager's name. Return columns: employee, manager. Order results by: e.id.
Return the 1 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 2 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 3 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 4 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 5 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 6 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 7 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
Return the 8 orders with the highest totals, including customer names. Return columns: order_id, customer_name, total_amount. Order results by: o.total_amount DESC, o.id.
List order items with quantity at least 1, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 2, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 3, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 4, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 5, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 6, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 7, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
List order items with quantity at least 8, including the product name. Return columns: order_id, product_name, quantity, unit_price. Order results by: oi.quantity DESC, oi.id.
Count each customer's orders placed on or after 2024-01-01. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-01-12. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-01-20. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-02-01. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-02-15. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-03-01. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-03-08. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
Count each customer's orders placed on or after 2024-03-12. Return columns: customer_name, order_count. Order results by: order_count DESC, customer_name.
For each marketplace, return active sellers that offer at least one active listing in every category required by that marketplace. Ignore marketplaces with no requirements. Return marketplace_id and seller_id ordered by both columns. Return columns: marketplace_id, seller_id.
Find canonical product pairs appearing together in at least two distinct completed baskets. Repeated lines for a product in one basket count once. Return product_a, product_b and basket_count, ordered by basket_count descending then product IDs. Return columns: product_a, product_b, basket_count.
Return every pair of subscriptions for the same customer whose inclusive active periods overlap. A NULL end_date means the subscription is still active. Return customer_id, subscription_a, subscription_b, overlap_start and overlap_end; use NULL overlap_end for an open-ended overlap. Return columns: customer_id, subscription_a, subscription_b, overlap_start, overlap_end.
For every order, select the customer's address version valid at ordered_at. Validity is inclusive at valid_from and exclusive at valid_to; NULL valid_to is open-ended. If versions share valid_from, choose the highest address_id. Return order_id, address_id and city. Return columns: order_id, address_id, city.
Show the complete escalation ownership for open tickets: assigned agent, that agent's team lead, and the lead's support director. Exclude tickets whose chain is incomplete. Return ticket_id, agent_name, lead_name and director_name. Return columns: ticket_id, agent_name, lead_name, director_name.
Find canonical pairs of active sales representatives who currently share at least two distinct customers. Duplicate assignment history must not inflate the count. Return rep_a, rep_b and shared_customers. Return columns: rep_a, rep_b, shared_customers.
Use a self LEFT JOIN to list every employee with their direct manager's first name. Return columns: id, first_name, manager_name. Order results by: e.id.
Reconcile ledger and scanner inventory movements by reference_code and product_id. Return records missing from either side or having different quantities. Emulate a full outer join in SQLite. Return reference_code, product_id, ledger_qty, scanner_qty and issue. Return columns: reference_code, product_id, ledger_qty, scanner_qty, issue.
A one-to-many or many-to-many relationship can produce multiple result rows for one source row. Check the join keys and the relationship cardinality.