SQL LABS: CHAPTERS 17–24
All records are invented. This is a separate teaching dataset from the
three-campaign CSV in earlier chapters: it has four campaigns and eight
leads. Never combine these totals with the earlier CSV.

Open a terminal in this sql folder, as taught in Chapter 15.
Windows: py setup_database.py
macOS/Linux: python3 setup_database.py
This creates harbour.db once. Existing databases are not overwritten.

Edit query.sql in a plain-text editor and save it. Run:
Windows: py run_query.py
macOS/Linux: python3 run_query.py

You may use IDLE: open setup_database.py and Run > Run Module once;
then open run_query.py and Run > Run Module after saving query.sql.
Run Module is normally F5 (some keyboards require Fn+F5).
The script finds query.sql in its own folder regardless of IDLE's folder.

To run a supplied query:
Windows: py run_query.py queries/18_filter.sql
macOS/Linux: python3 run_query.py queries/18_filter.sql
Each file holds one statement. The runner opens harbour.db read-only.

Chapter 23 standalone labs use only temporary in-memory databases:
py chapter23_integrity.py
py chapter23_parameters.py
py chapter23_plan.py
py chapter23_changes.py
(Substitute python3 on macOS/Linux.)

Checks: py test_sql.py (substitute python3 on macOS/Linux).
Solutions: queries/24_report.sql, queries/24_unknown.sql,
queries/24_reconciliation.sql. Read Chapter 24 before opening solutions.

Data definitions:
Campaign: one September 2026 campaign budget/activity, EUR cents.
Lead: one invented business enquiry/company in this small dataset.
Campaign ID NULL means attribution is unknown, not free acquisition.
Score NULL means not assessed; score 0 means assessed at zero.
Order: one order, paid or cancelled; amount is net teaching revenue,
no tax/shipping/returns represented. Paid status is accepted as recorded.
Dates are calendar dates, not timestamps; period ends are exclusive.
No customer contact details or real personal data appear in the lab.
