Free · In-browser · No signup

Practice SQL with
real company scenarios.

Click any question below, write SQL, run it live in your browser, and understand every concept in your language.

10 questions
⚠️ Note: These questions may or may not have been asked at the companies shown — the goal is to teach SQL through real-world usecases.
# Question Company Difficulty ✓
1
Find every pair of reservations for the same listing whose stay dates genuinely overlap — not reservations that simply share a listing, and not back-to-back turnovers where one checkout date equals the next check-in date. Treat a NULL check_out as an open-ended stay that hasn't ended yet (it overlaps with any later reservation on that listing). Return each overlapping pair once (not twice, and never a reservation paired with itself) as listing_id, guest_1, check_in_1, check_out_1, guest_2, check_in_2, check_out_2, sorted by listing_id then guest_1.
Self JOIN · COALESCE · JOIN
Airbnb mid
2
For each customer, calculate the total number of orders and total order amount per month. Treat any NULL order_amount as 0. Return customer_id, order_month (in YYYY-MM format), total_orders, and total_amount, sorted by customer_id and then order_month.
GROUP BY · strftime · COALESCE
Amazon easy
3
Return the product_name of every product in blinkit_products whose supplier_id has never appeared in blinkit_quality_flags — meaning that supplier has zero quality complaints on record. Use a NOT IN subquery against blinkit_quality_flags, and make sure the unresolved anonymous complaint (supplier_id IS NULL) doesn't wrongly disqualify every supplier. Sort by product_name.
NOT IN · Subquery · LEFT JOIN
Blinkit hard
4
Find every movie_title in this_week_screenings that is a brand new release — meaning it never appeared anywhere in last_week_screenings, across any city or showtime. Each movie should appear exactly once in the result, no matter how many screenings or cities it has this week. Return movie_title, sorted alphabetically.
INTERSECT · EXCEPT · UNION ALL
BookMyShow mid
5
Return car_model and the price as a number (aliased price) for every listing in cars24_listings priced above 500000. Use CAST to convert price_text to a numeric type before comparing — a plain string comparison on price_text gives the wrong answer. Sort by price descending.
CAST · WHERE · ORDER BY
Cars24 mid
6
For each user, find every reward category they have NOT successfully redeemed any points in this month — meaning either they have no redemption row for that category at all, or their only redemption row for that category has a NULL points_redeemed (a reversed attempt). Build the full user-times-category universe first, since a missed category has no row to start from in redemptions. Return user_name and category_name for every missed combination, sorted by user_name then category_name.
CROSS JOIN · LEFT JOIN · WHERE
CRED mid
7
Return awb, hub and pincode for every shipment whose PIN code is NOT a valid Indian PIN code — valid means it matches GLOB '[1-9][0-9][0-9][0-9][0-9][0-9]' (exactly 6 digits, first digit 1-9). A shipment with no PIN code at all (pincode IS NULL) must also be included. Order by awb.
GLOB · Character Classes · IS NULL
Delhivery mid
8
For each hub, return hub, shipments (all shipments), delivered (shipments with a non-NULL transit_days) and avg_transit_days (average transit_days, rounded to 2 decimals). Order fastest first by avg_transit_days ascending, but hubs with no deliveries yet (NULL average) must appear at the bottom — use NULLS LAST — and break ties by hub.
NULLS LAST · ORDER BY · AVG
Delhivery mid
9
Normalize dest_city with UPPER(TRIM(REPLACE(dest_city, ' ', ' '))) — collapse the double space, strip leading/trailing spaces, and make it upper case — and call it city. For each city return city, shipments (all shipments) and delivered (shipments whose transit_days is not NULL). Order by shipments descending, then city.
TRIM · UPPER · REPLACE
Delhivery easy
10
For each user in learning_activity, calculate total_xp as the sum of xp_earned (treating a NULL xp_earned, from a streak-freeze day, as 0). Calculate avg_xp_per_day as the average xp_earned across all logged days for that user, also treating NULL as 0 — a freeze day should pull the average down, not be excluded from it. Calculate language_count as the number of distinct languages the user has activity for, and languages_list as those distinct language names joined into a single comma-separated string, sorted alphabetically. Return user_name, total_xp, avg_xp_per_day (rounded to 2 decimal places), language_count, and languages_list, sorted by total_xp in descending order.
GROUP_CONCAT · COALESCE · COUNT(DISTINCT)
Duolingo mid