Learn the concept
A relational table stores rows with named columns. A primary key identifies a row; a foreign key expresses a relationship when enforced by the database configuration. Choose types and constraints to represent domain rules rather than leaving every rule to application code.
SELECT reads rows, WHERE filters, and ORDER BY defines order. Without an ordering clause, do not rely on rows arriving in a particular sequence. Parameterized queries keep values separate from SQL syntax and avoid treating user text as executable query structure.
Use SQLite for a local learning database. It does not make every production database behave identically, but it is enough to practice schema design, queries, and transactions. Close the connection when you finish; transaction handling and connection lifetime are separate concerns.
Run and inspect
import sqlite3
from contextlib import closing
with closing(sqlite3.connect(":memory:")) as db:
db.execute("CREATE TABLE tickets (id INTEGER PRIMARY KEY, title TEXT NOT NULL)")
db.execute("INSERT INTO tickets VALUES (?, ?)", (1, "User input"))
row = db.execute("SELECT title FROM tickets WHERE id = ?", (1,)).fetchone()
assert row == ("User input",)
Your exercise
Store three tickets and query one by ID using a parameter. Try a title containing quotes and verify it is stored as data.
Check your understanding
No query is assembled by interpolating untrusted values and missing IDs have an explicit result.