lesson 61 Database engineering · advanced
Constraints protect the data contract
Use constraints to reject data that breaks a rule.
the idea
Constraints are rules the database enforces on every write: NOT NULL forbids missing values, UNIQUE forbids duplicates, CHECK requires a condition, and FOREIGN KEY requires a matching parent row. A rejected write is the constraint working.
Dataset: Logistics
The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.
service_levels5 columns · 8 rows
| service_level_idnumber · unique id | service_codetext | service_nametext | promised_business_daysnumber | signature_requirednumber |
|---|---|---|---|---|
| 1 | GND | Ground | 5 | 0 |
| 2 | ECO | Ground Economy | 7 | 0 |
| 3 | 2DA | 2-Day | 2 | 0 |
| 4 | NDA | Next Day Air | 1 | 1 |
| 5 | SDY | Same Day | 0 | 1 |
| 6 | LTL | Freight LTL | 6 | 1 |
- service_level_idnumber · unique id
- 1
- service_codetext
- GND
- service_nametext
- Ground
- promised_business_daysnumber
- 5
- signature_requirednumber
- 0
- service_level_idnumber · unique id
- 2
- service_codetext
- ECO
- service_nametext
- Ground Economy
- promised_business_daysnumber
- 7
- signature_requirednumber
- 0
- service_level_idnumber · unique id
- 3
- service_codetext
- 2DA
- service_nametext
- 2-Day
- promised_business_daysnumber
- 2
- signature_requirednumber
- 0
- service_level_idnumber · unique id
- 4
- service_codetext
- NDA
- service_nametext
- Next Day Air
- promised_business_daysnumber
- 1
- signature_requirednumber
- 1
- service_level_idnumber · unique id
- 5
- service_codetext
- SDY
- service_nametext
- Same Day
- promised_business_daysnumber
- 0
- signature_requirednumber
- 1
- service_level_idnumber · unique id
- 6
- service_codetext
- LTL
- service_nametext
- Freight LTL
- promised_business_daysnumber
- 6
- signature_requirednumber
- 1
first 6 of 8 rows · your queries use all of them
packages8 columns · 11,505 rows
| package_idnumber · unique id | shipment_idnumber · links to shipments | tracking_numbertext | package_typetext | weight_kgdecimal | length_cmnumber | width_cmnumber | height_cmnumber |
|---|---|---|---|---|---|---|---|
| 1 | 1 | RT100007919B | box | 2.85 | 52 | 15 | 30 |
| 2 | 1 | RT100015838C | box | 1.1 | 69 | 45 | 24 |
| 3 | 2 | RT10 0023 757D | envelope | 0.49 | 32 | 24 | 2 |
| 4 | 3 | RT100031676E | box | 2.93 | 51 | 35 | 5 |
| 5 | 4 | RT100039595F | envelope | 0.38 | 32 | 24 | 3 |
| 6 | 5 | RT100047514G | box | 1.9 | 30 | 27 | 25 |
- package_idnumber · unique id
- 1
- shipment_idnumber · links to shipments
- 1
- tracking_numbertext
- RT100007919B
- package_typetext
- box
- weight_kgdecimal
- 2.85
- length_cmnumber
- 52
- width_cmnumber
- 15
- height_cmnumber
- 30
- package_idnumber · unique id
- 2
- shipment_idnumber · links to shipments
- 1
- tracking_numbertext
- RT100015838C
- package_typetext
- box
- weight_kgdecimal
- 1.1
- length_cmnumber
- 69
- width_cmnumber
- 45
- height_cmnumber
- 24
- package_idnumber · unique id
- 3
- shipment_idnumber · links to shipments
- 2
- tracking_numbertext
- RT10 0023 757D
- package_typetext
- envelope
- weight_kgdecimal
- 0.49
- length_cmnumber
- 32
- width_cmnumber
- 24
- height_cmnumber
- 2
- package_idnumber · unique id
- 4
- shipment_idnumber · links to shipments
- 3
- tracking_numbertext
- RT100031676E
- package_typetext
- box
- weight_kgdecimal
- 2.93
- length_cmnumber
- 51
- width_cmnumber
- 35
- height_cmnumber
- 5
- package_idnumber · unique id
- 5
- shipment_idnumber · links to shipments
- 4
- tracking_numbertext
- RT100039595F
- package_typetext
- envelope
- weight_kgdecimal
- 0.38
- length_cmnumber
- 32
- width_cmnumber
- 24
- height_cmnumber
- 3
- package_idnumber · unique id
- 6
- shipment_idnumber · links to shipments
- 5
- tracking_numbertext
- RT100047514G
- package_typetext
- box
- weight_kgdecimal
- 1.9
- length_cmnumber
- 30
- width_cmnumber
- 27
- height_cmnumber
- 25
first 6 of 11,505 rows · your queries use all of them
worked example
Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.
Build a table with CHECK rules. Run this. Valid zone rows insert cleanly; values outside the CHECK range would be rejected—that is the database enforcing the rule on every write.the pattern
example.sqlCREATE TABLE zone_codes (zone TEXT PRIMARY KEY, max_days INTEGER NOT NULL CHECK (max_days BETWEEN 0 AND 10)); INSERT INTO zone_codes VALUES ('A', 1), ('B', 3); SELECT * FROM zone_codes;
See the parent service levels. service_levels is what shipments reference. These ids and codes are the parent keys your foreign keys must match.
step-2.sqlSELECT service_level_id, service_code, promised_business_days FROM service_levels;
common mistake
A CHECK that allows NULL (weight_kg > 0) still lets a NULL weight in; add NOT NULL when the value is required.