Parameterised queries and the quote that breaks pasted SQL
A users table is a small version of a real app's customer list. Look at the last two queries: a value that merely looks like SQL is just a name nobody has, so it matches nothing.
Python can store data in a database through a driver. The built-in sqlite3 module needs no server; whatever the database, always pass values to SQL as parameters (placeholders), never by pasting text, and group changes in transactions so they succeed or fail together.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write find_user(conn, name) that returns the row for a name using a placeholder, or None if it does not exist.
Write add_user(conn, name, plan) that inserts a user inside with conn: and returns the new id (cursor.lastrowid).
Write count_by_plan(conn) returning a dictionary such as {'free': 2, 'pro': 1} using GROUP BY.
Explain it without notes
What is SQL injection and how do parameterised queries prevent it?
What is a transaction, and how does with conn: behave in sqlite3?
Why can you not use a placeholder for a table name, and what do you do instead?
What does row_factory = sqlite3.Row change?
A teammate builds a query with an f-string and says "it is only an internal tool". How do you respond?
Expected output
count: 3
safe lookup: (3, "O'Brien")
pasted SQL failed: near "Brien": syntax error
odd name matches: []
1 Asha {'id': 1, 'name': 'Asha', 'plan': 'free'}
3 O'Brien {'id': 3, 'name': "O'Brien", 'plan': 'free'}