Change rows and tables safely
INSERT, UPDATE, DELETE, ALTER and DROP, with a preview first
Where you are
Part II, after Exam 1
This chapter goes with Lab 10: From Paper to Database.
By the end you can add, change and remove rows on purpose, prove what changed and what did not, add a column or drop a table without losing facts you meant to keep, and say what a transaction promises.
A teammate at Northshore Coffee wants to raise tea prices by five percent. She writes UPDATE menu_items SET price = price * 1.05, runs it, and the engine reports success. It did exactly what she typed: every one of the 45 menu items is now five percent dearer, the sandwiches and the smoothies included, and nothing on the screen says so.
For nine chapters you have used one verb, SELECT, and it never changed anything. This chapter gives you the verbs that do. They are short, they run without complaint, and the only thing standing between a careful change and a mess is the WHERE you write and the SELECT you ran first.
Every exercise that changes data here runs on a disposable copy of the coffee database. Break it as often as you like; the next run starts fresh. Lab 10 asks you to do this for real, on a shelter database you build from a spec.
Two languages, one database
SQL has two families of verbs, and it helps to keep the names straight because the project checklist uses them. DML, data manipulation, is INSERT, UPDATE and DELETE (and SELECT): it changes the rows, and the tables stay as they were. DDL, data definition, is CREATE, ALTER and DROP: it changes the tables themselves, their columns, types and constraints.
A database you can rebuild is a database you can experiment on. The browser gives you that for free: each change-mode exercise opens a fresh copy, runs your one statement, and shows you what the copy looks like after. The desktop shell gives it to you too, as long as you keep the build script that made the database.
Rule of thumb. DML changes rows. DDL changes tables. Both run without asking twice.
Look first
SELECT id, name, size, price
FROM menu_items
WHERE category = 'Tea'
ORDER BY id;Before any UPDATE or DELETE, run a SELECT with the same WHERE. It shows you the exact rows the change will touch, it shows you how many, and it costs nothing. The tea raise's preview is SELECT id, name, price FROM menu_items WHERE category = 'Tea': seven rows. If the preview shows 45, the WHERE is wrong, and you found out before anything moved.
Then name the rows that must stay the same. 'Only tea changes' means 'coffee, pastries, sandwiches, smoothies and seasonal items do not', and that is a second SELECT you can run after the change to prove it. A change you cannot describe as 'these rows, and not those' is a change you are not ready to make.
Counts are not enough. changes() tells you how many rows a statement touched, and seven is the right number for the tea raise. Seven is also the number you get if you raise seven of the wrong items. Look at the rows, not only the count.
Rule of thumb. Preview with the same WHERE, name what must not change, then change.
Add a row that fits
INSERT INTO menu_items (name, category, size, price) VALUES ('Chai Latte', 'Tea', 'Large', 5.50) adds one row. Three habits live in that one statement. Name the columns: SQL lets you skip the column list and supply every value in table order, and every script that does so breaks the day someone adds a column. Leave id out: INTEGER PRIMARY KEY hands out the next number, and the row gets 46 because 45 was the last. Read changes() afterwards, or look at the row: one row, the one you meant.
INSERT INTO menu_items (name, category, size, price)
VALUES ('Chai Latte', 'Tea', 'Large', 5.50);A column you do not name gets its DEFAULT if the table has one, and NULL if it does not. calories, is_seasonal and description are not in the list above, so the new row has NULL in all three. That is fine when NULL means 'not recorded yet' and wrong when a report will treat it as zero.
Every constraint the table was created with is a rule about which inserts fail. A menu item with no name is refused: NOT NULL constraint failed: menu_items.name. An employee whose shop_id names a shop that does not exist is refused, once foreign keys are on: FOREIGN KEY constraint failed. The message names the rule that fired, which is why you paste error messages into reports as text: the wording is the diagnosis. A refused insert is not a failure of the exercise. It is the table doing its job, and you will write inserts that must fail on purpose in Lab 10.
Rule of thumb. Name the columns, leave the id out, and expect the table to refuse a row that breaks its rules.
Going deeper (optional, not on the exam)
The positional form, INSERT INTO menu_items VALUES (NULL, 'Chai Latte', 'Tea', 'Large', 5.50, NULL, NULL, NULL), runs. It also puts a value in the wrong column the day the table's column order changes, and nothing tells you.
Change only what you meant
UPDATE menu_items
SET price = ROUND(price * 1.05, 2)
WHERE category = 'Tea';UPDATE menu_items SET price = ROUND(price * 1.05, 2) WHERE category = 'Tea' raises seven prices. SET takes one or more column = value pairs, and the value can be an expression that uses the row's current values. WHERE picks the rows. Leave the WHERE off and the statement is still valid SQL, it still reports success, and it changes every row in the table. There is no confirmation step. The WHERE is the statement.
Read changes() immediately after. It is the number of rows the last statement touched, seven for the tea raise, 45 for the version without a WHERE. A zero means the WHERE matched nothing, which is a result to notice, not to accept.
An UPDATE has to satisfy every constraint an insert does. Set a price to NULL and the engine refuses: NOT NULL constraint failed, and the row is untouched.
Rule of thumb. An UPDATE without a WHERE changes every row and says nothing. Write the WHERE first.
Preview, then delete
SELECT COUNT(*) AS orders_left, MIN(order_date) AS earliest
FROM orders;DELETE FROM orders WHERE order_date < '2026-01-20' removes whole rows, 71 of them. The same two rules apply: preview with the same WHERE first, and read what remains. 204 orders minus 71 is 133, and SELECT COUNT(*), MIN(order_date) FROM orders afterwards should say 133 and 2026-01-20. If it says 122, your boundary ate the 20th.
DELETE with no WHERE empties the table, row by row, with no undo in the browser and no undo on the desktop either, unless you were inside a transaction. The disposable copy means you can try it once to see what 'no rows' looks like.
Rule of thumb. Preview the rows, delete them, then count and inspect what remains.
Going deeper (optional, not on the exam)
With foreign keys on, a parent row with children refuses to go: DELETE FROM employees WHERE id = 24 fails with FOREIGN KEY constraint failed, because seven orders point at that employee. The database is protecting the orders. What to do about them is a design decision, which chapter 6 and Lab 10 cover.
Change the shape, not the facts
ALTER TABLE employees
ADD COLUMN is_active INTEGER NOT NULL DEFAULT 1;ALTER TABLE shops ADD COLUMN manager_name TEXT adds a column to every existing row at once. Each row gets NULL in it, or the DEFAULT if you give one: ALTER TABLE employees ADD COLUMN is_active INTEGER NOT NULL DEFAULT 1 gives every employee a 1. A NOT NULL column with no DEFAULT is refused, because the existing rows would have nothing to hold, and so is a UNIQUE column: the engine cannot invent distinct values for rows that already exist.
DROP TABLE menu_items_old removes the table and every row in it, in one statement, with no undo. IF EXISTS makes a rerun harmless, which is why build scripts start with DROP TABLE IF EXISTS only when the author means 'start over'. With foreign keys on, a parent table that other tables point at refuses to be dropped: DROP TABLE shops fails while employees and orders reference it. Before you type DROP, say which table must never be dropped and why.
The browser engine is an older SQLite. It can add a column and drop a table. It cannot rename a column or drop one; the desktop SQLite you use for the labs can do both. For anything an ALTER cannot do, such as changing a column's type or adding a constraint to an existing column, the pattern on both engines is the rebuild: create the new table with the right definition, INSERT ... SELECT the rows across, drop the old table, rename the new one.
Rule of thumb. ADD COLUMN touches every row; DROP TABLE takes the rows with it. Decide which table is untouchable before you type.
Going deeper (optional, not on the exam)
A DROP that is refused by a foreign key is the delete rule again, one level up: the parent cannot go while children point at it. A DROP that succeeds on a table nobody references is final the moment it runs.
Both or neither
BEGIN;
INSERT INTO lessons VALUES (5, 1, 3, '2026-03-10', 60);
UPDATE guests SET balance = balance - 60 WHERE id = 1;
SELECT changes() AS guests_debited;
COMMIT;A coaching booking at Harbor Snow is two writes: insert the booking, debit the guest's prepaid balance. If the second one fails, the first one is a booking nobody paid for. A transaction makes the two succeed or fail together: BEGIN, both writes, check changes() and the balance, then COMMIT when it is right or ROLLBACK when it is not.
The part people get wrong: a failing statement inside a transaction does not undo the ones before it. When the debit is refused by the balance's CHECK, the transaction is still open and the booking insert is still pending. Nothing is committed and nothing is undone until you say which. The error is information; ROLLBACK is the decision.
The browser playground runs one statement at a time on a copy, so it cannot hold a transaction open. Transactions are a desktop skill: open the Harbor Snow kit in the sqlite3 shell, enter each statement separately, and watch the balances between them.
Rule of thumb. Inside a transaction an error pauses; it does not undo. You decide with COMMIT or ROLLBACK.
Going deeper (optional, not on the exam)
The sqlite3 shell's .bail on stops a script at the first error. That is not a rollback: everything before the error that was not inside a transaction has already happened. Use a fresh rehearsal copy to retry.
Concepts in this chapter
Each concept has its reading and a ladder of six rungs, from watching a question answered to transferring the idea to new data. The rungs below show your saved practice: reached, in progress or not yet.
Concept 1 · a SELECT with the same WHERE before any change
The preview would update every tea
- Write the SELECT that shows exactly the rows a change will touch
- Name the rows that must stay the same and check them afterwards
- Explain why a correct count is not proof of a correct change
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Concept 2 · INSERT with named columns, defaults, a parent that exists
Add a row that fits
- Insert a row by naming its columns and leaving the id out
- Say what an unnamed column receives
- Read a constraint failure as a diagnosis
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Concept 3 · UPDATE ... SET ... WHERE, and changes()
Change only what you meant
- Change one or more columns of exactly the rows the WHERE names
- Use the row's current value in the new value
- Catch a missing WHERE before it touches every row
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Concept 4 · DELETE ... WHERE, and what remains
Preview, then delete
- Delete exactly the rows the preview showed
- Prove what remains with a count and the earliest surviving row
- Explain why a referenced parent row refuses to go
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Concept 5 · ALTER TABLE ADD COLUMN, DROP TABLE IF EXISTS, what the engine cannot do
Change the shape, not the facts
- Add a column and say what every existing row gets in it
- Drop a table on purpose and make the script rerunnable
- Name the table that must never be dropped and why
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Concept 6 · BEGIN, COMMIT, ROLLBACK (desktop)
The error does not undo the first write
- Wrap two writes in one transaction and decide with COMMIT or ROLLBACK
- Say what state a transaction is in after a statement inside it fails
- Explain why the browser cannot practise this and the desktop can
- 1Watch it answered: not yet
- 2Fill the blank: not yet
- 3Predict the result: not yet
- 4Write it yourself: not yet
- 5Repair it: not yet
- 6Transfer it: not yet
Chapter review
Key terms
- DML
- Data manipulation: INSERT, UPDATE, DELETE and SELECT, the verbs that work on rows.
- DDL
- Data definition: CREATE, ALTER and DROP, the verbs that change tables themselves.
- changes()
- The number of rows the last statement touched.
- DEFAULT
- The value a column gets when an insert does not name it.
- transaction
- A group of statements that commit together or roll back together.
- ROLLBACK
- Undo everything since BEGIN; the decision to take when a statement inside a transaction fails.
Check your understanding
Short questions you can answer from the chapter. A choice shows its feedback at once; a sentence shows a model answer after you save it.
Opening your saved work…
Sign in to save across devices → · Download your guest work before switching accounts.
Applied to Lab 10
Part 3 of the lab makes a day's changes on the shelter database: an insert, an update, a delete. For each one, write the preview SELECT first, the statement second, and the SELECT that proves the untouched rows are untouched third. Paste all three into the report.
Sources and further reading
- Week 10 notes: Two Languages One Database, INSERT, UPDATE, DELETE, DDL, PRAGMA foreign_keys, and the common mistakes
- Pre-Lab 10
- The Harbor Snow reporting kit, transactions section