SQL · practice

The practice database

Every SQL lesson and interview problem uses these six small tables. The awkward cases are planted on purpose: NULLs, ties, duplicates, and a customer with no orders. Get to know the rows, and you can check any answer by eye.

Run any query

This box runs on a fresh copy of the database every time, so INSERT, UPDATE and DELETE are safe to try: nothing you do here can break a lesson.

Run any query on the practice database

Ctrl/⌘ + Enter runs it. Select part of the query to run only that part.

How the tables connect

erDiagram
  DEPARTMENTS ||--o{ EMPLOYEES : "has"
  EMPLOYEES |o--o{ EMPLOYEES : "manages"
  CUSTOMERS ||--o{ ORDERS : "places"
  ORDERS ||--o{ ORDER_ITEMS : "contains"
  PRODUCTS ||--o{ ORDER_ITEMS : "is in"
  DEPARTMENTS {
    int dept_id PK
    text dept_name
    text location
  }
  EMPLOYEES {
    int emp_id PK
    text name
    int dept_id FK
    int manager_id FK
    int salary
    text hire_date
  }
  CUSTOMERS {
    int customer_id PK
    text name
    text email
    text city
    text signup_date
  }
  ORDERS {
    int order_id PK
    int customer_id FK
    text order_date
    int amount
    text status
  }
  PRODUCTS {
    int product_id PK
    text product_name
    text category
    int price
  }
  ORDER_ITEMS {
    int order_id PK, FK
    int product_id PK, FK
    int quantity
  }
Each box is a table; PK marks its primary key and FK a foreign key. Read a line from left to right: one department has many employees, one customer places many orders, and order_items links orders to products, because one order can hold many products and one product can be in many orders. The loop on EMPLOYEES is manager_id pointing back into the same table.

The six tables

departments 4 rows

One row per department. HR has nobody in it yet.

dept_id PKdept_namelocation
1EngineeringLondon
2SalesManchester
3MarketingLondon
4HRLeeds
What each column means
  • dept_id INTEGER PRIMARY KEY: The department's id.
  • dept_name TEXT NOT NULL: Its name.
  • location TEXT: The city it is based in.

employees 8 rows

One row per employee. manager_id points at another row in this same table.

emp_id PKnamedept_id FKmanager_id FKsalaryhire_date
1Asha1NULL950002019-03-01
2Ben11700002020-06-15
3Chen11700002021-01-10
4Dara21600002020-02-20
5Eli24450002022-07-01
6Fatima31520002021-09-12
7GusNULL4380002023-04-03
8Hana12800002022-11-30
What each column means
  • emp_id INTEGER PRIMARY KEY: The employee's id.
  • name TEXT NOT NULL: First name.
  • dept_id INTEGER REFERENCES departments(dept_id): Their department. NULL for Gus.
  • manager_id INTEGER REFERENCES employees(emp_id): The emp_id of their manager. NULL for Asha, who has no manager.
  • salary INTEGER NOT NULL: Yearly salary in pounds.
  • hire_date TEXT NOT NULL: The day they joined (YYYY-MM-DD).

customers 6 rows

One row per sign-up. Tom signed up twice with the same email.

customer_id PKnameemailcitysignup_date
1Priyapriya@mail.comLondon2024-01-02
2Tomtom@mail.comLeeds2024-01-20
3Lenalena@mail.comLondon2024-01-30
4Omaromar@mail.comBristol2024-02-14
5Zoezoe@mail.comNULL2024-03-10
6Tomtom@mail.comLeeds2024-03-20
What each column means
  • customer_id INTEGER PRIMARY KEY: The customer's id.
  • name TEXT NOT NULL: First name.
  • email TEXT NOT NULL: Email address. Not unique, so duplicates can get in.
  • city TEXT: Home city. NULL for Zoe, who didn't say.
  • signup_date TEXT NOT NULL: The day they signed up.

orders 10 rows

One row per order. Order 106 was cancelled before an amount was recorded.

order_id PKcustomer_id FKorder_dateamountstatus
10112024-01-06120delivered
10212024-01-0780delivered
10312024-01-0845delivered
10422024-01-21200delivered
10512024-02-02150shipped
10632024-02-12NULLcancelled
10732024-02-2060delivered
10822024-03-0175delivered
10912024-03-1030delivered
11052024-03-1633pending
What each column means
  • order_id INTEGER PRIMARY KEY: The order's id.
  • customer_id INTEGER NOT NULL REFERENCES customers(customer_id): Who placed it.
  • order_date TEXT NOT NULL: The day it was placed.
  • amount INTEGER: The total in pounds. NULL for order 106.
  • status TEXT NOT NULL: delivered, shipped, cancelled or pending.

products 7 rows

One row per product. Nobody has bought the phone case.

product_id PKproduct_namecategoryprice
1PenStationery2
2NotebookStationery5
3MugKitchen8
4Desk lampHome25
5BackpackBags30
6HeadphonesElectronics40
7Phone caseElectronics15
What each column means
  • product_id INTEGER PRIMARY KEY: The product's id.
  • product_name TEXT NOT NULL: Its name.
  • category TEXT NOT NULL: The shop section it belongs to.
  • price INTEGER NOT NULL: Price in pounds.

order_items 14 rows

Which products are in which order, and how many. It links orders and products (many-to-many). Order 106 has no items.

order_id FKproduct_id FKquantity
10163
10242
10251
10335
10321
10465
10563
10551
10752
10843
10915
10924
11041
11031
What each column means
  • order_id INTEGER NOT NULL REFERENCES orders(order_id): The order.
  • product_id INTEGER NOT NULL REFERENCES products(product_id): The product.
  • quantity INTEGER NOT NULL: How many were bought.

My saved queries

Every query you change and run in any SQL lesson is saved in this browser, under the topic and the box you ran it in. Download my progress backs them up.

No saved queries yet.