Relate Tables Instead of Repeating Data · practice
Select the Available Items
The left-join report now gives each item one of two visible shapes:
| Item state | loan_id in the result |
|---|---|
| Has an active loan | A loan ID such as 501 |
| Has no active loan | NULL |
That missing joined ID is the evidence we need. Open report.sql and add this line before ORDER BY:
WHERE loans.id IS NULL
Press Run. The report should contain the folding table, projector screen, and repair kit. The drill and projector have active matches, so their loan IDs are not missing and those items do not pass the new filter.
The folding table is the useful boundary case. It has loan history, but its old row does not match the active-only ON. The left join therefore keeps the item with missing loan columns. WHERE loans.id IS NULL selects it as available alongside items that have never been borrowed.
Do not replace this filter with loans.returned_on IS NULL after the join. An active matched loan already has a NULL NULL in every joined loan column. That test would keep both borrowed and available items. Testing loans.id IS NULL distinguishes them: a matched loan has an ID, while a missing match does not. Keep the active-loan condition inside ON; the WHERE clause asks whether any such match was found.
The result remains ordered by items.asset_tag:
IT-200 | Folding table | NULL
IT-400 | Projector screen | NULL
IT-500 | Repair kit | NULL
Submit shuffles insertion order and uses active, returned-only, and never-loaned items. It expects only the latter two groups. The SQL values are not tested with Python truthiness, and = NULL cannot substitute for IS NULL.
You can now answer availability without storing a second availability flag. The current answer comes from the presence or absence of an active relationship, which cannot drift away from the loan history it summarizes.
Task
Add one WHERE report.sql that keeps items whose active left join found no loan row. Return only available items and preserve asset-tag order.