Practice SQL with SQLite
Twenty-eight exercises across sales, inventory and analytics. Start with SELECT and work up to JOINs and subqueries. Every exercise has a hint, a solution and an answer check that runs locally in your browser. No account required.
Follow a learning path · Explore all three datasets
Start with the sample shop
customers → orders → order_items ← products. There are 8 customers, 12 orders, 17 order items and 6 products. Use the Schema tab to inspect every column.
- Select customer names
Return name and country for every customer, ordered by id.
- Filter by country
Return name for customers in India, ordered by id.
- Compare numbers
Return name and price for products costing more than 60, ordered by price ascending, then id.
- Order by descending price
Return name and price for all products, most expensive first, then id.
- Find the top three
Return name and price for the three most expensive products, then id for ties.
- Find unique categories
Return each distinct product category in alphabetical order.
- Count orders
Return the total number of orders in one column.
- Sum order totals
Return the sum of all order totals in one column.
- Calculate an average
Return the average product price rounded to two decimal places.
- Group orders by status
Return status and order count, ordered alphabetically by status.
- Filter aggregated groups
Return customer_id and order count for customers with more than one order, ordered by customer_id.
- Connect customers and orders
Return order id and customer name for every order, ordered by order id.
- Count orders per customer
Return customer name and their order count for every customer, ordered by customer id.
- Find missing contact details
Return names of customers whose email is NULL, ordered by id. The sample may return no rows.
- Replace missing values
Return name and email, replacing NULL email with Unknown, ordered by id.
- Match part of a name
Return product names containing the word Desk, ordered by id.
- Choose a price range
Return name and price for products priced between 30 and 90 inclusive, ordered by id.
- Label expensive products
Return name and a label: Premium when price is at least 80, otherwise Standard. Order by id.
- Compare against the average
Return names of products priced above the average product price, ordered by id.
- Count units sold
Return product name and total quantity sold, ordered by product id.
- Find stock shortages
Return warehouse name, item name and quantity where quantity is below reorder_level, ordered by warehouse id and item id.
- Find items without stock records
Return item names with no stock row, ordered by item id.
- Total stock including missing items
Return every item name and total quantity, using zero for missing stock, ordered by item id.
- Calculate a running stock balance
Return movement id, item id, warehouse id and running balance ordered by movement id. Calculate balances separately for each item and warehouse.
- Count daily active users
Return date and distinct active user count for each day, ordered by date.
- Analyze device usage from JSON
Return device and event count, ordered by device.
- Find inactive users
Return user id and country for users without any events, ordered by user id.
- Rank event types per country
Return country, event name, event count and rank within country by count descending. Use DENSE_RANK and order by country then event name.