✍ 03: SQL Fundamentals — Exercises¶
Tip
Practice — try each question first, then expand the answer to check your reasoning. All questions use the Wedgewood Pacific schema: department(department_name, budget_code, office_number, department_phone), employee(employee_number, first_name, last_name, department_name, position, supervisor, office_phone, email_address), project(project_id, project_name, department_name, max_hours, start_date, end_date), assignment(project_id, employee_number, hours_worked).
Work through each question, then click ▶ Show answer to check yourself. Review the notes if you get stuck.
🔹 Q1. Write a statement that creates an assignment table with a composite primary key on (project_id, employee_number) and a CHECK constraint that hours_worked can never be negative.¶
Show answer
The `PRIMARY KEY (project_id, employee_number)` table constraint makes the *pair* unique — the same employee can appear on many projects, and the same project can have many employees, but each employee/project combination appears only once.❓ Q2. Write an INSERT statement that adds a new employee, Grace Lin, to InfoSystems, without listing every column in table order.¶
Show answer
Naming the column list explicitly means `position`, `supervisor`, and `office_phone` are simply left `NULL`, and the order you list columns in doesn't have to match the table's physical column order — it only has to match the order of the values.🔹 Q3. Write a query that lists every project in the Finance department with MaxHours greater than 130, sorted by start date.¶
Show answer
❓ Q4. Write a query that lists all employees whose position code matches the pattern "OPS" followed by exactly one digit (e.g., OPS1, OPS2, but not OPS10).¶
Show answer
`_` matches exactly one character, so `OPS_` matches `OPS1` and `OPS2` but not `OPS10` (which has an extra character) or `OPS` alone (which has none after the prefix).🔹 Q5. Write a query that lists every employee's office phone, showing 'Not on file' instead of a blank for anyone missing one.¶
Show answer
`COALESCE` returns the first non-`NULL` argument — here, the real phone number if one exists, otherwise the fallback text.❓ Q6. Write an inner join that lists each employee's first name, last name, and their department's office number.¶
Show answer
🔹 Q7. Write a query that finds every department that currently has no projects.¶
Show answer
This is the classic "find rows with no match" pattern: a `LEFT OUTER JOIN` keeps every department (even ones with zero projects, padded with `NULL`), and the `WHERE ... IS NULL` filter keeps only the padded rows — i.e., only the departments that matched nothing.❓ Q8. Write a self join that lists every employee alongside their supervisor's full name. Make sure the CEO (who has no supervisor) still appears in the results.¶
Show answer
The `LEFT OUTER JOIN` is required, not optional: the CEO has `supervisor = NULL`, and an `INNER JOIN` would silently drop her from the results because `NULL` never matches anything in the `ON` clause.🔹 Q9. Write a query that lists each project's name alongside the total hours logged against it, using assignment.¶
Show answer
Every column in `SELECT` that isn't wrapped in an aggregate (`p.project_name`) must appear in `GROUP BY` — otherwise SQL wouldn't know which single value to display for a project with multiple assignment rows.❓ Q10. Extend Q9 so it only shows projects where total logged hours exceed 100.¶
Show answer
`HAVING` filters *groups* after aggregation; `WHERE` filters individual *rows* before grouping and cannot reference an aggregate function like `SUM(...)`.🔹 Q11. Write a query using a subquery (not a join) that lists the names of employees who have at least one project assignment.¶
Show answer
The inner query returns the list of employee numbers that appear in `assignment`; the outer query keeps only employees whose number is in that list. This subquery can only ever display columns from `employee` (the outer table) — it could not also show `hours_worked` from `assignment` the way a join could.❓ Q12. Write a query using EXISTS that lists every department that has at least one project.¶
Show answer
This is a correlated subquery — it references `d.department_name` from the outer query, so it effectively re-checks "does at least one project exist for *this* department" once per department row. `EXISTS` only cares whether the subquery returns any row at all, not what value that row contains.📚 All Exercises · Next: Module 04 — Data Modeling & E-R Diagrams