CodeLiveStudio

SQL Practice Online: 15 Exercises on a Real Database

Quick answer

Work through 15 graded SQL practice exercises — SELECT, WHERE, ORDER BY, aggregates, GROUP BY, HAVING and JOINs — on a live SQLite database with departments, employees and projects. Every exercise has a solution and expected output, and the playground runs your query instantly in the browser.

Reviewed by the CodeLive Studio team

Reading about SQL teaches the words; practicing SQL teaches the reflexes. The fastest loop is a real database in the browser: write a query, press Run, see the rows. The exercises below use exactly the sample database that ships with the playground on this site — three tables, ten employees, five departments, five projects — so every expected result here is what you will actually see. Nothing to install, nothing to sign up for, and the schema is one click away whenever you forget a column name.

The practice database: 3 tables, 20 rows

Every exercise runs against this schema. It is deliberately small enough to verify by eye but has the two ingredients real practice needs: a foreign key to join on (dept_id) and a second join target (projects) for the harder exercises.

The schema you will be querying
departments(dept_id, dept_name)              -- 5 rows
employees(emp_id, name, dept_id, salary, hired)  -- 10 rows
projects(project_id, title, dept_id, budget)     -- 5 rows

-- employees quick view:
--  Engineering: Ada 9500, Grace 10200, Turing 8800
--  Design:      Paula 7600, Massimo 7200
--  Marketing:   Seth 6400, Ogilvy 6900
--  Sales:       Zig 5800, Mary 6100
--  HR:          Patty 5400

Beginner exercises: SELECT, WHERE and ORDER BY

Warm up with single-table queries. Type each one into the playground, press Run, and compare against the expected result before moving on. If a row is missing from your result, the WHERE clause is the first suspect.

Solution for exercise 2
SELECT name, salary
FROM employees
WHERE salary > 7000
ORDER BY salary DESC;
#ExerciseExpected result
1List every column of every employee10 rows, all columns
2List only the names and salaries of employees earning over 70005 rows: Grace, Ada, Turing, Paula, Massimo
3Show employees sorted by salary, highest firstGrace 10200 first, Patty 5400 last
4Find employees hired in 20222 rows: Seth (2022-02-01), Patty (2022-10-03)
5Count how many employees there are in totalOne row, value 10

Intermediate exercises: aggregates, GROUP BY and HAVING

Aggregates collapse rows into answers. The mental model that makes GROUP BY click: it first splits the table into buckets, then computes the aggregate once per bucket, and HAVING filters the buckets afterward — which is why aggregate conditions go in HAVING, never in WHERE.

Solution for exercise 6 (the classic JOIN + GROUP BY)
SELECT d.dept_name,
       ROUND(AVG(e.salary), 0) AS avg_salary
FROM employees e
JOIN departments d ON d.dept_id = e.dept_id
GROUP BY d.dept_name
ORDER BY avg_salary DESC;
#ExerciseExpected result
6Average salary per department, with the department name5 rows; Engineering 9500, Design 7400, Marketing 6650, Sales 5950, HR 5400
7Headcount per department, largest firstEngineering 3, then Design/Marketing/Sales/HR 2/2/2/1
8Departments where average salary exceeds 6500, using HAVING3 rows: Engineering, Design, Marketing
9Total project budget across all departmentsOne row, 136000
10Earliest and latest hire date in one queryOne row: 2018-07-02 and 2023-04-17

Advanced exercises: multi-table JOINs and subqueries

These mirror interview questions. Exercise 11 is the money query — it joins three tables and aggregates across two of them. If your numbers are off by rows, check whether you are counting employees or projects: the two GROUP BYs answer different questions with the same shape.

Solution for exercise 13 (correlated subquery)
SELECT name, salary, dept_id
FROM employees e
WHERE salary > (
  SELECT AVG(salary)
  FROM employees
  WHERE dept_id = e.dept_id
)
ORDER BY salary DESC;
#ExerciseExpected result
11Total payroll and headcount per department, joined with departments5 rows; Engineering leads with 28500 across 3 people
12Department names that have a project with budget over 30000Engineering, Marketing (use DISTINCT)
13Employees whose salary is above their department average (subquery)Grace (10200 > 9500), Paula (7600 > 7400), Ogilvy (6900 > 6650), Mary (6100 > 5950)
14The second-highest salary without using LIMIT twiceOne row: 9500 (Ada)
15Departments with no projects (LEFT JOIN + IS NULL)No rows — all five departments have a project; rewrite with NOT EXISTS to prove it

How to run these queries right now

Open the SQL playground and the sample database is already loaded — departments, employees and projects, exactly as described above. Type or paste an exercise query into the editor, press Run, and the result table appears below with row counts. The playground is real SQLite (compiled to WebAssembly), so JOINs, subqueries, HAVING and SQLite-specific functions like ROUND all behave as documented here.

A practical study loop that works: attempt the query before looking at any solution, run it, compare rows to the expected column in the tables above, and only then read the answer. When your result differs, shrink the query — strip the JOIN, then the WHERE — until the intermediate result shows you exactly where the rows went missing.

Questions this guide answers

  • sql practice
  • sql practice online
  • practice sql questions
  • sql exercises with solutions
  • sql join practice
  • sql group by exercises
  • sql playground online free
  • practice sql online free

Frequently asked questions

Can I practice SQL online for free without installing anything?

Yes. The playground on this site runs a real SQLite engine compiled to WebAssembly, entirely in your browser. There is no account, no usage limit and no upload — the database lives in your tab, resets on reload, and exercises like the ones on this page run in milliseconds.

Which SQL dialect do these exercises use?

SQLite. It covers everything these exercises need — joins, aggregates, subqueries, HAVING — and its syntax is close enough to PostgreSQL or MySQL that the solutions transfer almost unchanged. The main dialect differences you would meet elsewhere are date functions and string concatenation operators.

Is this enough practice to prepare for SQL interview questions?

It is a solid start: exercises 11 through 13 mirror the three most common interview patterns — multi-table aggregation, EXISTS/DISTINCT reasoning and correlated subqueries. For depth, the real skill is adapting: once a query returns the right rows, modify it (add a second condition, switch the sort) until you can predict the output before running it.

What is the difference between WHERE and HAVING?

WHERE filters individual rows before grouping; HAVING filters the groups after aggregation. That is why exercise 8 uses HAVING AVG(salary) > 6500 — the average does not exist until after GROUP BY, so it cannot appear in a WHERE clause.

How do I reset the sample database if I modify the data?

Reload the page — the sample schema and rows are re-created fresh every time the playground loads. You can also re-run the schema script from the Sample button at any time, which restores the original three tables and their 20 rows.

Can I use my own data for SQL practice?

Yes — the playground accepts full CREATE TABLE and INSERT statements, so you can paste your own schema and query it the same way. The sample database simply guarantees that the expected outputs in these exercises match what you see, which is what makes them gradeable.