๐Ÿ—„๏ธ
Practice environment: Go to sqliteonline.com โ†’ paste the setup SQL below โ†’ run it โ†’ then attempt each exercise. Or use SQLite on your machine: sqlite3 lab.db

Database Setup

Run this SQL first โ€” it creates the tables and sample data you'll query throughout the lab.

-- Paste this entire block into sqliteonline.com and click Run

CREATE TABLE employees (
    id         INTEGER PRIMARY KEY,
    name       TEXT,
    department TEXT,
    salary     REAL,
    hire_date  TEXT,
    manager_id INTEGER
);

CREATE TABLE departments (
    id       INTEGER PRIMARY KEY,
    name     TEXT,
    location TEXT,
    budget   REAL
);

CREATE TABLE projects (
    id          INTEGER PRIMARY KEY,
    name        TEXT,
    department  TEXT,
    status      TEXT,
    budget      REAL,
    start_date  TEXT
);

CREATE TABLE assignments (
    employee_id INTEGER,
    project_id  INTEGER,
    role        TEXT,
    hours       INTEGER
);

INSERT INTO departments VALUES
(1,'Engineering','London',500000),
(2,'Marketing','Manchester',200000),
(3,'Sales','Birmingham',350000),
(4,'HR','London',150000);

INSERT INTO employees VALUES
(1,'Alice Johnson','Engineering',75000,'2020-03-15',NULL),
(2,'Bob Smith','Marketing',55000,'2019-07-22',NULL),
(3,'Charlie Brown','Engineering',68000,'2021-01-10',1),
(4,'Diana Prince','Sales',62000,'2018-11-30',NULL),
(5,'Eve Wilson','Engineering',82000,'2017-05-20',1),
(6,'Frank Miller','HR',48000,'2022-02-14',NULL),
(7,'Grace Lee','Marketing',59000,'2020-09-01',2),
(8,'Henry Ford','Sales',71000,'2016-04-08',4),
(9,'Iris Chen','Engineering',90000,'2015-12-01',1),
(10,'Jack Davis','Sales',53000,'2023-06-15',4);

INSERT INTO projects VALUES
(1,'Website Redesign','Engineering','Active',80000,'2024-01-01'),
(2,'Social Campaign','Marketing','Active',30000,'2024-02-15'),
(3,'CRM Migration','Engineering','Completed',120000,'2023-06-01'),
(4,'Sales Training','HR','Active',15000,'2024-03-01'),
(5,'Mobile App','Engineering','Active',200000,'2024-01-15'),
(6,'Brand Refresh','Marketing','Paused',45000,'2024-04-01');

INSERT INTO assignments VALUES
(1,1,'Lead',120),(1,5,'Reviewer',40),
(3,1,'Developer',200),(3,3,'Developer',80),
(5,3,'Lead',150),(5,5,'Lead',300),
(9,1,'Architect',60),(9,5,'Architect',100),
(2,2,'Manager',180),(7,2,'Designer',140),
(4,4,'Trainer',80),(6,4,'Coordinator',60),
(8,4,'Attendee',20),(10,4,'Attendee',20);

Exercises 1โ€“5: SELECT Basics

Exercise 1

Select all columns from the employees table.

Show Answer
SELECT * FROM employees;

Exercise 2

Select only the name and salary columns from employees, and rename them in the output as "Employee Name" and "Annual Salary".

Show Answer
SELECT name AS "Employee Name", salary AS "Annual Salary"
FROM employees;

Exercise 3

Show all unique department names from the employees table (no duplicates).

Show Answer
SELECT DISTINCT department FROM employees;

Exercise 4

List all employees ordered by salary from highest to lowest. Show name and salary only.

Show Answer
SELECT name, salary
FROM employees
ORDER BY salary DESC;

Exercise 5

Show the top 3 highest-paid employees (name, department, salary).

Show Answer
SELECT name, department, salary
FROM employees
ORDER BY salary DESC
LIMIT 3;

Exercises 6โ€“10: Filtering with WHERE

Exercise 6

Find all employees in the Engineering department.

Show Answer
SELECT * FROM employees WHERE department = 'Engineering';

Exercise 7

Find all employees earning more than ยฃ65,000 who are in Engineering or Sales. Show name, department, and salary.

Show Answer
SELECT name, department, salary
FROM employees
WHERE salary > 65000
AND department IN ('Engineering', 'Sales')
ORDER BY salary DESC;

Exercise 8

Find all employees hired between 2019 and 2021 (inclusive). Show name, hire_date, department.

Show Answer
SELECT name, hire_date, department
FROM employees
WHERE hire_date BETWEEN '2019-01-01' AND '2021-12-31'
ORDER BY hire_date;

Exercise 9

Find all employees whose name starts with a vowel (A, E, I, O, U).

Show Answer
SELECT name FROM employees
WHERE name LIKE 'A%'
   OR name LIKE 'E%'
   OR name LIKE 'I%'
   OR name LIKE 'O%'
   OR name LIKE 'U%';

Exercise 10

Find all employees who do NOT have a manager (manager_id is NULL).

Show Answer
SELECT name, department FROM employees
WHERE manager_id IS NULL;

Exercises 11โ€“15: Aggregation & Grouping

Exercise 11

Count the total number of employees and find the average, minimum, and maximum salary.

Show Answer
SELECT
    COUNT(*)         AS total_employees,
    ROUND(AVG(salary), 2) AS avg_salary,
    MIN(salary)      AS lowest_salary,
    MAX(salary)      AS highest_salary
FROM employees;

Exercise 12

Show the number of employees and average salary per department. Order by average salary descending.

Show Answer
SELECT
    department,
    COUNT(*) AS headcount,
    ROUND(AVG(salary), 2) AS avg_salary,
    SUM(salary) AS total_payroll
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;

Exercise 13

Find departments where the total payroll (sum of salaries) exceeds ยฃ200,000.

Show Answer
SELECT department, SUM(salary) AS total_payroll
FROM employees
GROUP BY department
HAVING total_payroll > 200000
ORDER BY total_payroll DESC;

Exercise 14

Show the total hours worked per project (from the assignments table). Show project_id and total hours, ordered by hours descending.

Show Answer
SELECT project_id, SUM(hours) AS total_hours
FROM assignments
GROUP BY project_id
ORDER BY total_hours DESC;

Exercise 15

Find how many projects are in each status (Active, Completed, Paused).

Show Answer
SELECT status, COUNT(*) AS project_count
FROM projects
GROUP BY status
ORDER BY project_count DESC;

Exercises 16โ€“20: JOINs

Exercise 16

Show each employee's name along with the projects they are assigned to (project name, not just ID). Use a JOIN.

Show Answer
SELECT e.name AS employee, p.name AS project, a.role
FROM employees e
JOIN assignments a ON e.id = a.employee_id
JOIN projects   p ON p.id = a.project_id
ORDER BY e.name;

Exercise 17

Show all Engineering employees and how many projects each one is assigned to (including 0 if none). Use LEFT JOIN.

Show Answer
SELECT e.name, COUNT(a.project_id) AS projects_count
FROM employees e
LEFT JOIN assignments a ON e.id = a.employee_id
WHERE e.department = 'Engineering'
GROUP BY e.id
ORDER BY projects_count DESC;

Exercise 18

Find the total hours worked by each employee across all their projects. Show name, department, total hours. Include employees with no hours (0).

Show Answer
SELECT e.name, e.department, COALESCE(SUM(a.hours), 0) AS total_hours
FROM employees e
LEFT JOIN assignments a ON e.id = a.employee_id
GROUP BY e.id
ORDER BY total_hours DESC;

Exercise 19

List all active projects with their department budget (from the departments table) and how many employees are assigned to each project.

Show Answer
SELECT
    p.name AS project,
    p.status,
    d.budget AS dept_budget,
    p.budget AS project_budget,
    COUNT(a.employee_id) AS team_size
FROM projects p
JOIN departments d ON d.name = p.department
LEFT JOIN assignments a ON a.project_id = p.id
WHERE p.status = 'Active'
GROUP BY p.id
ORDER BY team_size DESC;

Exercise 20 โ€” Boss Level

Find the highest-paid employee in each department, along with their total hours worked across all projects and number of projects. Sort by salary descending.

Show Answer
SELECT
    e.name,
    e.department,
    e.salary,
    COALESCE(SUM(a.hours), 0)       AS total_hours,
    COUNT(DISTINCT a.project_id)     AS project_count
FROM employees e
LEFT JOIN assignments a ON e.id = a.employee_id
WHERE e.salary = (
    SELECT MAX(e2.salary)
    FROM employees e2
    WHERE e2.department = e.department
)
GROUP BY e.id
ORDER BY e.salary DESC;
๐Ÿ†
Lab Complete! SQL mastery comes with practice on real data. Try exploring public datasets on kaggle.com or data.gov. Also study SQL injection attacks to understand why parameterised queries matter.
โ† SQL Workbook All Labs
// guided terminal

Try It Live

Type the commands from the steps above. The terminal simulates the expected output for this lab.

KaliRange ~ Terminal type help for commands