FREE SQL PRACTICE · BEGINNER TO ADVANCED

SQL Practice Online: 30 Exercises with Answers

The fastest way to learn SQL is to write queries on a real table and check the result. These 30 SQL practice exercises use one small shop database (customers, products, orders, order items and employees). Every answer below was run in SQLite, and its result table is shown, so you can compare your output row by row. Open any query in the free browser playground with one click. No sign-up, nothing to install.

हिन्दी में समझें

यहाँ 30 SQL अभ्यास प्रश्न हैं, आसान से कठिन तक। हर सवाल का उत्तर और उसका परिणाम (result table) दिया गया है। "Run in playground" दबाकर क्वेरी अपने ब्राउज़र में चलाइए। कोई लॉगिन या इंस्टॉल नहीं।

The practice database

All exercises use the same fictional shop. Keep this list open while you write queries.

TableColumnsRows
customersid, name, city6
productsid, name, category, price5
ordersid, customer_id, order_date, status8
order_itemsorder_id, product_id, quantity11
employeesid, name, department, salary, manager_id6

Engine: SQLite 3.49 running in your browser. Queries that change data only affect a temporary copy.

Beginner SQL practice questions

SELECT, WHERE, ORDER BY, LIMIT, DISTINCT, LIKE and calculated columns.

1Show every column and row from the customers table.

customers टेबल की सभी पंक्तियाँ और कॉलम दिखाएँ।

Hint

Use SELECT * with FROM.

Show answer and result
SELECT * FROM customers;
idnamecity
1AshaDelhi
2RaviMumbai
3NehaDelhi
4KabirPune
5MeeraJaipur
6ZoyaChennai
Run in playground →

2Show only the name and price of every product.

हर product का केवल name और price दिखाएँ।

Hint

List the columns after SELECT, separated by commas.

Show answer and result
SELECT name, price FROM products;
nameprice
Python Book500
SQL Book400
Keyboard1200
Mouse600
Notebook100
Run in playground →

3List the cities where customers live, without repeats.

ग्राहकों के शहर बिना दोहराव के दिखाएँ।

Hint

DISTINCT removes duplicate values.

Show answer and result
SELECT DISTINCT city FROM customers;
city
Delhi
Mumbai
Pune
Jaipur
Chennai
Run in playground →

4Find all customers who live in Delhi.

दिल्ली में रहने वाले सभी ग्राहक खोजें।

Hint

Filter rows with WHERE and put text in single quotes.

Show answer and result
SELECT name, city FROM customers WHERE city = 'Delhi';
namecity
AshaDelhi
NehaDelhi
Run in playground →

5Show products that cost more than 500.

500 से महंगे products दिखाएँ।

Hint

Use a comparison operator in WHERE.

Show answer and result
SELECT name, price FROM products WHERE price > 500;
nameprice
Keyboard1200
Mouse600
Run in playground →

6List products from the most expensive to the cheapest.

products को सबसे महंगे से सस्ते क्रम में दिखाएँ।

Hint

ORDER BY ... DESC sorts from high to low.

Show answer and result
SELECT name, price FROM products ORDER BY price DESC;
nameprice
Keyboard1200
Mouse600
Python Book500
SQL Book400
Notebook100
Run in playground →

7Show the two cheapest products.

सबसे सस्ते दो products दिखाएँ।

Hint

Sort ascending, then LIMIT the rows.

Show answer and result
SELECT name, price FROM products ORDER BY price ASC LIMIT 2;
nameprice
Notebook100
SQL Book400
Run in playground →

8Show each product with its price including 18% tax, named price_with_tax.

हर product की 18% tax सहित कीमत price_with_tax नाम से दिखाएँ।

Hint

Multiply by 1.18 and rename the column with AS.

Show answer and result
SELECT name, price, ROUND(price * 1.18, 2) AS price_with_tax FROM products;
namepriceprice_with_tax
Python Book500590
SQL Book400472
Keyboard12001416
Mouse600708
Notebook100118
Run in playground →

9Find orders that are paid or pending.

paid या pending orders खोजें।

Hint

IN checks a column against a list of values.

Show answer and result
SELECT id, status FROM orders WHERE status IN ('paid', 'pending');
idstatus
1paid
2paid
3pending
4paid
5paid
7paid
8pending
Run in playground →

10Find customers whose name starts with the letter K or M.

जिन ग्राहकों का नाम K या M से शुरू होता है, उन्हें खोजें।

Hint

LIKE with % matches any following text.

Show answer and result
SELECT name FROM customers WHERE name LIKE 'K%' OR name LIKE 'M%';
name
Kabir
Meera
Run in playground →

Intermediate SQL practice questions

COUNT, SUM, AVG, MIN, MAX, GROUP BY, HAVING, INNER JOIN, LEFT JOIN and multi-table totals.

11How many orders are there in total?

कुल कितने orders हैं?

Hint

COUNT(*) counts rows.

Show answer and result
SELECT COUNT(*) AS total_orders FROM orders;
total_orders
8
Run in playground →

12Count orders by status.

हर status के orders गिनें।

Hint

GROUP BY makes one row per status.

Show answer and result
SELECT status, COUNT(*) AS orders FROM orders GROUP BY status;
statusorders
cancelled1
paid5
pending2
Run in playground →

13Show the average salary in each department, highest first.

हर department की औसत salary, सबसे ज़्यादा पहले दिखाएँ।

Hint

AVG with GROUP BY, then ORDER BY the average.

Show answer and result
SELECT department, ROUND(AVG(salary), 0) AS avg_salary FROM employees GROUP BY department ORDER BY avg_salary DESC;
departmentavg_salary
Engineering80000
Data70000
Operations50000
Run in playground →

14Which categories have more than one product?

किन categories में एक से ज़्यादा product हैं?

Hint

HAVING filters groups after GROUP BY.

Show answer and result
SELECT category, COUNT(*) AS products FROM products GROUP BY category HAVING COUNT(*) > 1;
categoryproducts
Books2
Tech2
Run in playground →

15Show the cheapest and the most expensive price in each category.

हर category की सबसे कम और सबसे ज़्यादा कीमत दिखाएँ।

Hint

MIN and MAX work inside GROUP BY.

Show answer and result
SELECT category, MIN(price) AS lowest, MAX(price) AS highest FROM products GROUP BY category;
categorylowesthighest
Books400500
Stationery100100
Tech6001200
Run in playground →

16Show every order with the customer name.

हर order के साथ ग्राहक का नाम दिखाएँ।

Hint

INNER JOIN orders to customers on customer_id = customers.id.

Show answer and result
SELECT o.id AS order_id, c.name, o.status FROM orders o JOIN customers c ON c.id = o.customer_id ORDER BY o.id;
order_idnamestatus
1Ashapaid
2Ravipaid
3Ashapending
4Nehapaid
5Kabirpaid
6Ravicancelled
7Meerapaid
8Nehapending
Run in playground →

17List every customer and how many orders they placed, including customers with no orders.

हर ग्राहक के orders की संख्या दिखाएँ, जिनका कोई order नहीं उन्हें भी।

Hint

LEFT JOIN keeps every customer; COUNT(o.id) counts only matched orders.

Show answer and result
SELECT c.name, COUNT(o.id) AS orders FROM customers c LEFT JOIN orders o ON o.customer_id = c.id GROUP BY c.id, c.name ORDER BY orders DESC, c.name;
nameorders
Asha2
Neha2
Ravi2
Kabir1
Meera1
Zoya0
Run in playground →

18Find customers who have never placed an order.

जिन ग्राहकों ने कभी order नहीं किया, उन्हें खोजें।

Hint

LEFT JOIN and keep rows where the order id IS NULL.

Show answer and result
SELECT c.name FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.id IS NULL;
name
Zoya
Run in playground →

19Show total quantity sold for each product.

हर product की कुल बिकी quantity दिखाएँ।

Hint

Join order_items to products and SUM the quantity.

Show answer and result
SELECT p.name, SUM(oi.quantity) AS qty_sold FROM order_items oi JOIN products p ON p.id = oi.product_id GROUP BY p.id, p.name ORDER BY qty_sold DESC;
nameqty_sold
Notebook15
SQL Book4
Python Book3
Keyboard3
Mouse3
Run in playground →

20Calculate the value of each order (quantity x price).

हर order की value (quantity × price) निकालें।

Hint

Join order_items with products, multiply, then SUM per order.

Show answer and result
SELECT oi.order_id, SUM(oi.quantity * p.price) AS order_value FROM order_items oi JOIN products p ON p.id = oi.product_id GROUP BY oi.order_id ORDER BY oi.order_id;
order_idorder_value
12200
21600
3500
42400
5900
6600
71000
8800
Run in playground →

Advanced SQL practice questions

Monthly totals with dates, CASE labels, subqueries, self joins, NOT EXISTS, CTEs and window functions: RANK, running totals and LAG.

21Show revenue from paid orders only, by month.

सिर्फ paid orders का revenue महीने के हिसाब से दिखाएँ।

Hint

strftime('%Y-%m', order_date) gives the month in SQLite.

Show answer and result
SELECT strftime('%Y-%m', o.order_date) AS month, SUM(oi.quantity * p.price) AS revenue FROM orders o JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id WHERE o.status = 'paid' GROUP BY month ORDER BY month;
monthrevenue
2026-016200
2026-021900
Run in playground →

22Label each product as Premium (price 1000 or more), Standard (300 to 999) or Budget.

हर product को Premium, Standard या Budget लेबल दें।

Hint

CASE WHEN ... THEN ... ELSE ... END creates labels.

Show answer and result
SELECT name, price, CASE WHEN price >= 1000 THEN 'Premium' WHEN price >= 300 THEN 'Standard' ELSE 'Budget' END AS price_band FROM products;
namepriceprice_band
Python Book500Standard
SQL Book400Standard
Keyboard1200Premium
Mouse600Standard
Notebook100Budget
Run in playground →

23Find employees who earn more than the company average salary.

कंपनी की औसत salary से ज़्यादा कमाने वाले employees खोजें।

Hint

Compare salary with a subquery that returns AVG(salary).

Show answer and result
SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
namesalary
Tara90000
Om70000
Ira80000
Run in playground →

24Show each employee with their manager's name.

हर employee के साथ उसके manager का नाम दिखाएँ।

Hint

Self join: join employees to employees on manager_id.

Show answer and result
SELECT e.name AS employee, m.name AS manager FROM employees e LEFT JOIN employees m ON m.id = e.manager_id ORDER BY e.id;
employeemanager
TaraNULL
OmTara
IraTara
DevIra
PiaTara
SamPia
Run in playground →

25Find the highest-paid employee in each department.

हर department का सबसे ज़्यादा salary वाला employee खोजें।

Hint

Use a correlated subquery or a window function.

Show answer and result
SELECT department, name, salary FROM employees e WHERE salary = (SELECT MAX(salary) FROM employees WHERE department = e.department) ORDER BY department;
departmentnamesalary
DataIra80000
EngineeringTara90000
OperationsPia50000
OperationsSam50000
Run in playground →

26Rank employees by salary inside each department.

हर department के अंदर employees को salary से rank करें।

Hint

RANK() OVER (PARTITION BY ... ORDER BY ...).

Show answer and result
SELECT department, name, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank FROM employees ORDER BY department, dept_rank;
departmentnamesalarydept_rank
DataIra800001
DataDev600002
EngineeringTara900001
EngineeringOm700002
OperationsPia500001
OperationsSam500001
Run in playground →

27Show a running total of order value by order date (paid orders).

paid orders की value का running total तारीख के क्रम में दिखाएँ।

Hint

Build order values in a CTE, then SUM(...) OVER (ORDER BY ...).

Show answer and result
WITH v AS (SELECT o.id, o.order_date, SUM(oi.quantity * p.price) AS value FROM orders o JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id WHERE o.status = 'paid' GROUP BY o.id, o.order_date) SELECT order_date, value, SUM(value) OVER (ORDER BY order_date) AS running_total FROM v ORDER BY order_date;
order_datevaluerunning_total
2026-01-0222002200
2026-01-0316003800
2026-01-0624006200
2026-02-019007100
2026-02-0510008100
Run in playground →

28Find the top customer by total spend on paid orders.

paid orders पर सबसे ज़्यादा खर्च करने वाला ग्राहक खोजें।

Hint

Join four tables, SUM per customer, ORDER BY DESC, LIMIT 1.

Show answer and result
SELECT c.name, SUM(oi.quantity * p.price) AS total_spend FROM customers c JOIN orders o ON o.customer_id = c.id JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id WHERE o.status = 'paid' GROUP BY c.id, c.name ORDER BY total_spend DESC LIMIT 1;
nametotal_spend
Neha2400
Run in playground →

29Find customers who have never bought a Tech product.

जिन ग्राहकों ने कभी Tech product नहीं खरीदा, उन्हें खोजें।

Hint

NOT EXISTS checks that no matching row exists in a joined subquery.

Show answer and result
SELECT c.name FROM customers c WHERE NOT EXISTS (SELECT 1 FROM orders o JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id WHERE o.customer_id = c.id AND p.category = 'Tech') ORDER BY c.name;
name
Kabir
Meera
Zoya
Run in playground →

30For each order, show the customer's previous order date and the days since then.

हर order के लिए उसी ग्राहक के पिछले order से कितने दिन हुए, दिखाएँ।

Hint

LAG() returns the previous row's value; julianday() turns dates into numbers.

Show answer and result
SELECT c.name, o.order_date, LAG(o.order_date) OVER (PARTITION BY o.customer_id ORDER BY o.order_date) AS previous_order, CAST(julianday(o.order_date) - julianday(LAG(o.order_date) OVER (PARTITION BY o.customer_id ORDER BY o.order_date)) AS INTEGER) AS days_gap FROM orders o JOIN customers c ON c.id = o.customer_id ORDER BY c.name, o.order_date;
nameorder_dateprevious_orderdays_gap
Asha2026-01-02NULLNULL
Asha2026-01-052026-01-023
Kabir2026-02-01NULLNULL
Meera2026-02-05NULLNULL
Neha2026-01-06NULLNULL
Neha2026-02-082026-01-0633
Ravi2026-01-03NULLNULL
Ravi2026-02-032026-01-0331
Run in playground →

How to use these SQL exercises

  1. Read the question and try the query yourself first, in the playground.
  2. Use the hint only if you are stuck for more than two minutes.
  3. Compare your result with the answer table: same rows, same order where ORDER BY is used.
  4. Change one thing (a filter, a column, a join type) and predict the new result before you run it.
  5. Finished all 30? Take the free SQL course and its final test to earn a completion certificate.

SQL practice FAQ

Where can I practise SQL online for free?

On this page. Read an exercise, write your query, then open it in the free Excel Keys SQL playground. It runs SQLite inside your browser, so there is nothing to install and no sign-up.

Which SQL is used in these exercises?

SQLite. Most queries here also work in MySQL, PostgreSQL and SQL Server. Date functions such as strftime and julianday are SQLite-specific, and the answers say so where it matters.

Are these SQL exercises good for interview preparation?

They cover the topics most beginner and analyst interviews test: filtering, sorting, GROUP BY with HAVING, joins including LEFT JOIN, subqueries, CASE, window functions such as RANK and LAG, and running totals.

Is my query or data uploaded anywhere?

No. The playground runs on your device. Your queries and any changes to the sample tables stay in your browser and reset when you reload.

Can I get a certificate?

Yes. Finish the free 32-lesson SQL course and its final test in LearnLab to download an Excel Keys completion certificate. It is a self-paced completion certificate, not an accredited qualification.

References & corrections

Full language rules are in the official SQLite documentation. Window functions are described in SQLite window functions. Found a mistake? Tell us with the exercise number.

FROM LEARNING TO BUSINESS RESULTS

Need a dashboard for your team?

Excel Keys designs custom Excel and HTML dashboards around your own KPIs and Excel files. They run offline in the browser, so your data stays on your computer.