The SQL Sample Database
Every lesson in this tutorial queries the same small company database, so you can focus on SQL instead of new data each time. It has six related tables: a company’s departments and employees, and its online shop’s customers, products, orders and order items. This page shows every row and gives you the script to create it on your own MySQL server.
- What each table holds and how the tables are linked
- Which rows make interesting edge cases (NULLs, unmatched rows, ties)
- How to create the database on your own server
How the tables are linked
| Table | Primary key | Links to | Rows |
|---|---|---|---|
departments | dept_id | 5 | |
employees | emp_id | dept_id → departments, manager_id → employees | 12 |
customers | customer_id | 7 | |
products | product_id | 9 | |
orders | order_id | customer_id → customers | 10 |
order_items | order_id + product_id | order_id → orders, product_id → products | 16 |
- HR side: each employee belongs to a department and reports to a manager, who is also an employee (
manager_idpoints back toemployees). The chain goes four levels deep: CEO → manager → senior developer → developer. - Shop side: a customer places orders; each order has one or more order items; each item is a product with a quantity. Line amount =
quantity × price.
departments
| dept_id | dept_name | location |
|---|---|---|
| 1 | Engineering | Bengaluru |
| 2 | Sales | Mumbai |
| 3 | Marketing | Pune |
| 4 | HR | Delhi |
| 5 | Finance | Mumbai |
Finance (dept 5) has no employees: useful for LEFT JOIN examples.
employees
| emp_id | first_name | last_name | dept_id | manager_id | job_title | salary | commission | hire_date | city |
|---|---|---|---|---|---|---|---|---|---|
| 100 | Meera | Kapoor | NULL | NULL | CEO | 250000 | NULL | 2015-01-05 | Mumbai |
| 101 | Asha | Rao | 1 | 100 | Engineering Manager | 125000 | NULL | 2018-04-12 | Bengaluru |
| 102 | Rahul | Mehta | 1 | 101 | Senior Developer | 98000 | NULL | 2019-07-01 | Bengaluru |
| 103 | Priya | Nair | 1 | 101 | QA Engineer | 72000 | NULL | 2021-01-18 | Pune |
| 104 | Karan | Shah | 1 | 102 | Developer | 72000 | NULL | 2022-08-29 | Bengaluru |
| 105 | Vikram | Singh | 2 | 100 | Sales Manager | 105000 | 12000 | 2017-11-20 | Mumbai |
| 106 | Neha | Gupta | 2 | 105 | Sales Executive | 54000 | 6000 | 2022-03-14 | Mumbai |
| 107 | Arjun | Das | 2 | 105 | Sales Executive | 48000 | 4500 | 2023-06-05 | Kolkata |
| 108 | Kavya | Iyer | 3 | 100 | Marketing Lead | 88000 | NULL | 2020-09-09 | Pune |
| 109 | Rohan | Joshi | 3 | 108 | Content Writer | 45000 | NULL | 2024-01-22 | Pune |
| 110 | Sneha | Kulkarni | 4 | 100 | HR Manager | 78000 | NULL | 2019-02-25 | Delhi |
| 111 | Amit | Verma | 1 | 101 | Intern | 25000 | NULL | 2025-06-02 | Bengaluru |
Rows worth noticing:
- Meera Kapoor (100), the CEO, has no department and no manager (
NULL). - Priya Nair and Karan Shah both earn 72,000: a tie, which matters for RANK and DENSE_RANK.
- Only the three Sales staff have a
commission; it isNULLfor everyone else (NULL Values).
customers
| customer_id | customer_name | city | joined_on | |
|---|---|---|---|---|
| 1 | Ananya Sharma | ananya@example.com | Mumbai | 2024-01-15 |
| 2 | Rohit Kumar | rohit.k@example.com | Delhi | 2024-02-03 |
| 3 | Fatima Khan | fatima@example.com | Hyderabad | 2024-03-21 |
| 4 | David Fernandes | NULL | Goa | 2024-05-09 |
| 5 | Ishita Bose | ishita@example.com | Kolkata | 2024-07-30 |
| 6 | Manoj Pillai | manoj.p@example.com | Chennai | 2025-01-11 |
| 7 | Sara Thomas | sara.t@example.com | Bengaluru | 2025-03-02 |
David Fernandes has no email, and Manoj Pillai and Sara Thomas have never ordered.
products
| product_id | product_name | category | price | stock |
|---|---|---|---|---|
| 1 | Wireless Mouse | Electronics | 799 | 120 |
| 2 | Mechanical Keyboard | Electronics | 3499 | 45 |
| 3 | USB-C Hub | Electronics | 1999 | 0 |
| 4 | Office Chair | Furniture | 8999 | 12 |
| 5 | Standing Desk | Furniture | 18999 | 5 |
| 6 | Notebook Pack | Stationery | 249 | 300 |
| 7 | Gel Pens | Stationery | 199 | 250 |
| 8 | Desk Lamp | Furniture | 1499 | 30 |
| 9 | Monitor Arm | Furniture | 2799 | 18 |
The USB-C Hub is out of stock (stock = 0), and the Monitor Arm has never been ordered.
orders
| order_id | customer_id | order_date | status |
|---|---|---|---|
| 1001 | 1 | 2025-01-05 | Delivered |
| 1002 | 2 | 2025-01-17 | Delivered |
| 1003 | 1 | 2025-02-02 | Delivered |
| 1004 | 3 | 2025-02-14 | Cancelled |
| 1005 | 4 | 2025-03-08 | Delivered |
| 1006 | 5 | 2025-03-22 | Shipped |
| 1007 | 2 | 2025-04-10 | Delivered |
| 1008 | 1 | 2025-04-28 | Pending |
| 1009 | 3 | 2025-05-15 | Delivered |
| 1010 | 5 | 2025-06-01 | Delivered |
order_items
| order_id | product_id | quantity |
|---|---|---|
| 1001 | 2 | 1 |
| 1001 | 6 | 5 |
| 1002 | 4 | 1 |
| 1003 | 1 | 1 |
| 1003 | 2 | 1 |
| 1004 | 5 | 1 |
| 1005 | 6 | 10 |
| 1005 | 7 | 4 |
| 1006 | 3 | 2 |
| 1006 | 8 | 1 |
| 1007 | 1 | 1 |
| 1008 | 4 | 2 |
| 1008 | 8 | 2 |
| 1009 | 2 | 1 |
| 1010 | 6 | 3 |
| 1010 | 7 | 2 |
A first look across the tables
How much did each order cost? This joins three tables. You will learn every part of it in the coming lessons:
SELECT o.order_id, c.customer_name, o.status, SUM(oi.quantity * p.price) AS order_totalFROM orders oJOIN customers c ON c.customer_id = o.customer_idJOIN order_items oi ON oi.order_id = o.order_idJOIN products p ON p.product_id = oi.product_idGROUP BY o.order_id, c.customer_name, o.statusORDER BY o.order_id;| order_id | customer_name | status | order_total |
|---|---|---|---|
| 1001 | Ananya Sharma | Delivered | 4744 |
| 1002 | Rohit Kumar | Delivered | 8999 |
| 1003 | Ananya Sharma | Delivered | 4298 |
| 1004 | Fatima Khan | Cancelled | 18999 |
| 1005 | David Fernandes | Delivered | 3286 |
| 1006 | Ishita Bose | Shipped | 5497 |
| 1007 | Rohit Kumar | Delivered | 799 |
| 1008 | Ananya Sharma | Pending | 20996 |
| 1009 | Fatima Khan | Delivered | 3499 |
| 1010 | Ishita Bose | Delivered | 1145 |
FROM orders ostarts from the 10 orders (ois a short alias).- The three
JOINs attach the customer, the order’s items and each item’s product. quantity * priceis the amount of one line;SUM(...)adds the lines of each order.GROUP BYmakes one result row per order, andORDER BYsorts by order number.
Create it on your own server
Create the database, select it, then run the script below (copy it into the mysql client, MySQL Workbench or any SQL tool):
CREATE DATABASE company;USE company;-- sqatools.in SQL tutorial: the "company" sample database (runs unchanged on MySQL 8.4 and SQLite)CREATE TABLE departments ( dept_id INT PRIMARY KEY, dept_name VARCHAR(50) NOT NULL, location VARCHAR(50));INSERT INTO departments VALUES(1, 'Engineering', 'Bengaluru'),(2, 'Sales', 'Mumbai'),(3, 'Marketing', 'Pune'),(4, 'HR', 'Delhi'),(5, 'Finance', 'Mumbai'); CREATE TABLE employees ( emp_id INT PRIMARY KEY, first_name VARCHAR(30) NOT NULL, last_name VARCHAR(30) NOT NULL, dept_id INT, manager_id INT, job_title VARCHAR(40), salary INT, commission INT, hire_date DATE, city VARCHAR(30), FOREIGN KEY (dept_id) REFERENCES departments (dept_id));INSERT INTO employees VALUES(100, 'Meera', 'Kapoor', NULL, NULL, 'CEO', 250000, NULL, '2015-01-05', 'Mumbai'),(101, 'Asha', 'Rao', 1, 100, 'Engineering Manager', 125000, NULL, '2018-04-12', 'Bengaluru'),(102, 'Rahul', 'Mehta', 1, 101, 'Senior Developer', 98000, NULL, '2019-07-01', 'Bengaluru'),(103, 'Priya', 'Nair', 1, 101, 'QA Engineer', 72000, NULL, '2021-01-18', 'Pune'),(104, 'Karan', 'Shah', 1, 102, 'Developer', 72000, NULL, '2022-08-29', 'Bengaluru'),(105, 'Vikram', 'Singh', 2, 100, 'Sales Manager', 105000, 12000, '2017-11-20', 'Mumbai'),(106, 'Neha', 'Gupta', 2, 105, 'Sales Executive', 54000, 6000, '2022-03-14', 'Mumbai'),(107, 'Arjun', 'Das', 2, 105, 'Sales Executive', 48000, 4500, '2023-06-05', 'Kolkata'),(108, 'Kavya', 'Iyer', 3, 100, 'Marketing Lead', 88000, NULL, '2020-09-09', 'Pune'),(109, 'Rohan', 'Joshi', 3, 108, 'Content Writer', 45000, NULL, '2024-01-22', 'Pune'),(110, 'Sneha', 'Kulkarni', 4, 100, 'HR Manager', 78000, NULL, '2019-02-25', 'Delhi'),(111, 'Amit', 'Verma', 1, 101, 'Intern', 25000, NULL, '2025-06-02', 'Bengaluru'); CREATE TABLE customers ( customer_id INT PRIMARY KEY, customer_name VARCHAR(50) NOT NULL, email VARCHAR(60), city VARCHAR(30), joined_on DATE);INSERT INTO customers VALUES(1, 'Ananya Sharma', 'ananya@example.com', 'Mumbai', '2024-01-15'),(2, 'Rohit Kumar', 'rohit.k@example.com', 'Delhi', '2024-02-03'),(3, 'Fatima Khan', 'fatima@example.com', 'Hyderabad', '2024-03-21'),(4, 'David Fernandes', NULL, 'Goa', '2024-05-09'),(5, 'Ishita Bose', 'ishita@example.com', 'Kolkata', '2024-07-30'),(6, 'Manoj Pillai', 'manoj.p@example.com', 'Chennai', '2025-01-11'),(7, 'Sara Thomas', 'sara.t@example.com', 'Bengaluru', '2025-03-02'); CREATE TABLE products ( product_id INT PRIMARY KEY, product_name VARCHAR(50) NOT NULL, category VARCHAR(30), price INT, stock INT);INSERT INTO products VALUES(1, 'Wireless Mouse', 'Electronics', 799, 120),(2, 'Mechanical Keyboard', 'Electronics', 3499, 45),(3, 'USB-C Hub', 'Electronics', 1999, 0),(4, 'Office Chair', 'Furniture', 8999, 12),(5, 'Standing Desk', 'Furniture', 18999, 5),(6, 'Notebook Pack', 'Stationery', 249, 300),(7, 'Gel Pens', 'Stationery', 199, 250),(8, 'Desk Lamp', 'Furniture', 1499, 30),(9, 'Monitor Arm', 'Furniture', 2799, 18); CREATE TABLE orders ( order_id INT PRIMARY KEY, customer_id INT NOT NULL, order_date DATE NOT NULL, status VARCHAR(20) NOT NULL, FOREIGN KEY (customer_id) REFERENCES customers (customer_id));INSERT INTO orders VALUES(1001, 1, '2025-01-05', 'Delivered'),(1002, 2, '2025-01-17', 'Delivered'),(1003, 1, '2025-02-02', 'Delivered'),(1004, 3, '2025-02-14', 'Cancelled'),(1005, 4, '2025-03-08', 'Delivered'),(1006, 5, '2025-03-22', 'Shipped'),(1007, 2, '2025-04-10', 'Delivered'),(1008, 1, '2025-04-28', 'Pending'),(1009, 3, '2025-05-15', 'Delivered'),(1010, 5, '2025-06-01', 'Delivered'); CREATE TABLE order_items ( order_id INT, product_id INT, quantity INT NOT NULL, PRIMARY KEY (order_id, product_id), FOREIGN KEY (order_id) REFERENCES orders (order_id), FOREIGN KEY (product_id) REFERENCES products (product_id));INSERT INTO order_items VALUES(1001, 2, 1), (1001, 6, 5),(1002, 4, 1),(1003, 2, 1), (1003, 1, 1),(1004, 5, 1),(1005, 6, 10), (1005, 7, 4),(1006, 3, 2), (1006, 8, 1),(1007, 1, 1),(1008, 4, 2), (1008, 8, 2),(1009, 2, 1),(1010, 6, 3), (1010, 7, 2);The script uses only standard types (INT, VARCHAR, DATE), so it also runs unchanged on SQLite and needs only small changes for PostgreSQL or SQL Server.
Sample database FAQ
Where can I get a sample database to practise SQL?
Copy the script on this page into MySQL to get the six-table company database used in every lesson of this tutorial. It is small enough to check every result by hand.
Why does the sample data contain NULLs and unmatched rows?
Real data is messy. An employee without a department, customers without orders and a product never sold are exactly the cases that make joins, NULL handling and aggregates behave differently, so every lesson can show them.
Can I change the sample data?
Yes. Run INSERT, UPDATE and DELETE freely; to start over, drop the database and run the script again. The Try it editors in the lessons always start from a fresh copy.