Boneyard Tools

Practice SQL joins and aggregates in the browser

Use the preloaded employees and departments tables to learn joins, GROUP BY and aggregate functions with runnable examples you can edit live.

The two sample tables

The playground seeds a departments table and an employees table linked by a foreign key. Departments holds four rows, Engineering, Design, Sales and Support, each with a floor number. Employees holds ten people, and every row carries a department_id that points back at a department id, plus a title, salary and hire date. That single relationship is enough to practice the core of everyday SQL: filtering rows, joining tables and summarizing groups. Click a table name in the sidebar to browse its rows before you start writing queries.

Joining employees to departments

A join stitches related rows from two tables into one result. Because each employee stores only a department_id number, you join to departments to see the readable department name. Running SELECT e.name, e.title, d.name AS department FROM employees e JOIN departments d ON d.id = e.department_id ORDER BY d.name, e.name pairs every person with their department and sorts the list. The ON clause is the matching rule, and aliasing the tables as e and d keeps the query short. This inner join returns only employees that have a matching department, which here is all ten.

Summarizing with GROUP BY

Aggregate functions collapse many rows into one summary value, and GROUP BY says which rows to bucket together. To get headcount and average pay per department, group by the department name and apply COUNT and AVG. The Average salary by department example returns Engineering with 4 people at 155750, Design with 2 at 141500, Sales with 2 at 107000, and Support with 2 at 90000, ordered from highest average down. ROUND trims the average to a whole number. Swap AVG for MIN, MAX or SUM to answer different questions from the same shape of query.

Filtering and ordering results

WHERE filters rows before grouping, ORDER BY sorts the output, and LIMIT caps how many rows come back. The Hired since 2021 example, SELECT name, hired_on FROM employees WHERE hired_on >= '2021-01-01' ORDER BY hired_on, returns Alan Turing, Radia Perlman, Howard Schultz and Kathy Sierra in date order because the dates are stored as sortable YYYY-MM-DD text. Combine these clauses freely: filter to one department, group the survivors, and limit to the top few. Every example is editable, so change a value, press Cmd or Ctrl plus Enter, and watch the grid update instantly.

Frequently asked questions

What is the difference between WHERE and HAVING?

WHERE filters individual rows before they are grouped. HAVING filters the grouped results after aggregation, so you use HAVING to keep only groups whose COUNT or AVG meets a condition.

Why use table aliases like e and d?

Aliases shorten long table names and are required when the same column name appears in both tables, such as name here. Writing e.name and d.name makes it unambiguous which table each column comes from.

How do I keep the changes I make to the sample?

Run your INSERTs or ALTERs, then click Download database to save a .sqlite file. Reloading the page resets the in memory copy, so exporting is the only way to persist edits.