Before this lesson

Understand INSERT, transactions, types and NULL. Parameter binding is performed through a caller API.

What you will be able to do

Reject invalid references and duplicate keys and understand parameter binding.

Understand the mechanism

Application validation improves feedback; database constraints protect all write paths. NOT NULL, UNIQUE, CHECK and FOREIGN KEY address missing values, duplicates, business predicates and relationships respectively.

Enable and verify SQLite foreign_keys on each connection before beginning a transaction. Ordinary SQLite type affinity is not strict typing, so this schema additionally checks typeof(minutes).

Bind external values through the driver, for example Python connection.execute("SELECT name FROM courses WHERE id = ?", (course_id,)). Placeholders bind values, not table names or sort keywords; select dynamic identifiers from an explicit allowlist.

Runnable example

This course uses SQLite 3. Open a fresh in-memory database, for example with sqlite3 :memory:, and run the complete script. Each lesson supplies its own schema and sample data, independent of the website database.

PRAGMA foreign_keys=ON;
CREATE TABLE courses(id INTEGER PRIMARY KEY,name TEXT NOT NULL UNIQUE);
CREATE TABLE sessions(
 id INTEGER PRIMARY KEY,
 course_id INTEGER NOT NULL REFERENCES courses(id),
 minutes INTEGER NOT NULL CHECK(typeof(minutes)='integer' AND minutes BETWEEN 0 AND 240)
);
INSERT INTO courses VALUES(1,'Python');
INSERT INTO sessions VALUES(1,1,25);
SELECT course_id,minutes FROM sessions;

Trace and verify

The valid record is course 1 with 25 minutes. Independently try course_id=99, minutes=-1 and minutes=NULL to observe rejected writes.

Common mistakes and boundaries

A CHECK result of NULL is not a failed check, which is why NOT NULL is separate. The application must decide and execute rollback behavior after constraint errors.

Practice challenge

Try inserting a second course named Python and explain why the error is not a foreign-key failure.

Reference solution and reasoning

INSERT INTO courses VALUES(2,'Python'); violates UNIQUE on name. The new id is distinct; the duplicate name is the cause.

Further reading