From reading to writing
Everything so far has been read-only: you asked Daybreak questions and it answered. The commands in this session actually change data - they are how the rows got there in the first place. This is where analysts become builders: you can now stand up a table, seed it, correct it, and evolve it. And here is the safety net that makes learning this painless - every Run in this course starts from a clean, freshly seeded copy of the database. Your writes are real while the query runs, then they vanish. No box affects another box, and no learner affects another learner.
CREATE TABLE, INSERT, UPDATE, DELETE - plus ALTER TABLE and the single most clarifying idea in SQL: the query does not run in the order you wrote it. Once you see the real execution order, half of SQL's "why won't this work" mysteries dissolve.
CREATE TABLE, data types, and keys 6 min live
A table is a promise about shape: these columns, these types, these rules. CREATE TABLE writes that promise. Each column gets a type (INTEGER, TEXT, REAL), and you can attach constraints - PRIMARY KEY to guarantee each row is uniquely identifiable, NOT NULL to forbid missing values, FOREIGN KEY to point at another table's key.
LiveBuild a table from nothing, then fill it3 min▶
This editor starts from an empty database - no Daybreak tables at all - so you can watch a table come into existence. It creates roasters, inserts two rows, then reads them back. Press ▶ Run, then add a third roaster to the INSERT and run again.
CREATE TABLE roasters ( roaster_id INTEGER PRIMARY KEY, name TEXT NOT NULL, country TEXT ); INSERT INTO roasters VALUES (1,'Highland','Kenya'),(2,'Volcanica','Costa Rica'); SELECT * FROM roasters;
Types catch bugs at the door. A team once stored prices as TEXT to "keep it simple". Sorting by price then ordered them alphabetically - "100" came before "9" - and a discount script silently mis-ranked the catalog for weeks. Declaring price REAL would have made the data wrong-shaped and loud, not quietly wrong.
Self-studyPRIMARY KEY vs FOREIGN KEY, in one breath2 min read▶
Two keys, two jobs. A PRIMARY KEY answers "which row is this?" - it is unique and never NULL, so it names each record. A FOREIGN KEY answers "which row over there does this point at?" - it holds a value that must exist as a primary key in another table. In Daybreak, customers.customer_id is a primary key; orders.customer_id is the matching foreign key, and that pairing is exactly what every JOIN from b4 rode on.
- PRIMARY KEY: one per table, unique + not null. The row's identity.
- FOREIGN KEY: a pointer to another table's key. Keeps relationships honest.
- Together: they are why you can store a customer's city once and still attach it to 40 orders - the JOIN follows the key.
INSERT, UPDATE, DELETE 8 min live
Three verbs change rows. INSERT adds them, UPDATE edits values in rows that already exist, DELETE removes rows. Each box below runs on a fresh seeded copy of Daybreak, so you can hit real customer and order data safely - do the write, then a SELECT right after to see the effect, then run again knowing the next run resets everything.
LiveINSERT - add a new customer3 min▶
Daybreak signs up a test buyer. We add one row to customers, then read it back to confirm it landed. The SELECT filters to just the new id so you see exactly what changed.
INSERT INTO customers VALUES (99,'Test Buyer','Oslo','Norway','2026-06-15','Pro'); SELECT * FROM customers WHERE customer_id = 99;
Values line up with the column order: id, name, city, country, signup_date, plan. Get the order right and every field lands in its place.
LiveUPDATE - a coffee price bump3 min▶
Every coffee goes up by one. UPDATE touches existing rows; the WHERE decides which ones. Here it is every product in the Coffee category - Equipment and Add-ons are left alone.
UPDATE products SET price = price + 1 WHERE category='Coffee'; SELECT name, price FROM products WHERE category='Coffee';
UPDATE or DELETE with no WHERE hits every row. On this page that just resets next run - in production it is the classic outage story. Habit to build now: write the WHERE first, then the SET.
LiveDELETE - clear out cancelled orders3 min▶
DELETE removes whole rows. We drop every cancelled order, then count what remains. Because the copy is fresh each run, the original 33 orders are always back on the next Run.
DELETE FROM orders WHERE status='cancelled'; SELECT COUNT(*) AS remaining FROM orders;
Soft delete beats hard delete. Many teams never truly DELETE customer or order rows - they add a status or is_deleted flag and UPDATE it instead, so history stays auditable and mistakes are reversible. Notice Daybreak already does a version of this: cancelled and refunded orders are kept, just marked - so revenue queries can exclude them without losing the record.
ALTER TABLE and the real order of execution 7 min live
ALTER TABLE changes a table's structure after it exists - add a column, rename it, drop it. And then the idea that reorganizes how you read every query you have written: SQL does not run top to bottom the way you type it. The engine runs FROM first and SELECT almost last.
LiveALTER a table - add a column, then use it3 min▶
Starts from an empty database. We make a bare tmp table with one column, then ALTER it to add a label column, insert a row that uses both, and read it back. Watch the table's shape change without dropping and rebuilding it.
CREATE TABLE tmp (id INTEGER); ALTER TABLE tmp ADD COLUMN label TEXT; INSERT INTO tmp VALUES (1,'hello'); SELECT * FROM tmp;
UPDATE changes the values inside rows. ALTER changes the table's structure - the columns themselves. Editing a customer's city is UPDATE; adding a whole "loyalty_tier" column is ALTER.
Self-studyWhy execution order saves you from bugs2 min read▶
Two classic errors both come from forgetting the real order. First: you alias SUM(quantity*unit_price) AS revenue in SELECT, then try WHERE revenue > 100 - and it fails, because WHERE ran before SELECT existed. The fix is HAVING revenue > 100, which runs after grouping. Second: you cannot filter on a window-function result in WHERE for the same reason - windows compute at SELECT time. Once the numbered pipeline is in your head, these stop being surprises and start being predictable.
- Filter raw rows?
WHERE- it runs early, before grouping. - Filter groups or aggregates?
HAVING- it runs after GROUP BY. - Rename for output? Aliases in SELECT are for ORDER BY and the result, not for WHERE.
Stand up a mini table and evolve it ★ 10 min · everyone builds
Put all four verbs together on a fresh, empty database. Create a small promos table, seed it, correct a value, remove a stale row, then reshape it - the full lifecycle a builder runs every week.
CREATE TABLE promos (code TEXT PRIMARY KEY, pct INTEGER); - a promo code and its discount percent.
INSERT INTO promos VALUES ('SPRING',10),('WELCOME',15); - two live promos.
UPDATE promos SET pct = 20 WHERE code='WELCOME'; - bump the welcome offer.
ALTER TABLE promos ADD COLUMN active TEXT; then read it back - the shape evolved.
CREATE TABLE promos (code TEXT PRIMARY KEY, pct INTEGER);
INSERT INTO promos VALUES ('SPRING',10),('WELCOME',15);
UPDATE promos SET pct = 20 WHERE code='WELCOME';
ALTER TABLE promos ADD COLUMN active TEXT;
SELECT * FROM promos;
This is a migration. When engineers "ship a migration", this is literally what runs: a scripted sequence of CREATE / ALTER / UPDATE against the real database, version-controlled and reviewed. The verbs you just used are the exact same ones powering the schema changes behind every product you use - the difference is only scale and a review step.
Try it yourself - this week ◐ 20-30 min total
- On a
data-seed="none"box, create asupplierstable with an id (PRIMARY KEY), a name (NOT NULL), and a country. Insert three suppliers and read them back. - On a fresh seeded box, INSERT a new product into
products, then UPDATE its price, then DELETE it - proving to yourself the copy resets each run. - Write an UPDATE that gives every "Pro" customer a note - first add a
notecolumn with ALTER, then UPDATE it WHERE plan='Pro'. - Say out loud, without looking, the seven-step execution order. Then explain why you cannot put a SELECT alias in WHERE.
- Bring one question to b9: if you were handed Daybreak cold, how would you find out why March revenue dropped? Next session answers exactly that.
Official sources covered
This session teaches the data-definition and data-modification core of the major free SQL curricula, run on live data instead of screenshots. Graded problem sets stay on the official sites. This page covers:
Three questions before you go 🎯 ◐ 90 seconds
1 · You run an INSERT in one editor on this page. What happens to the next editor?
Each Run executes against a fresh seeded copy. Your INSERT / UPDATE / DELETE is real for that run, then gone - no box or learner affects another.
2 · What is the difference between UPDATE and ALTER?
UPDATE edits data in existing rows. ALTER reshapes the table itself - adding, renaming, or dropping columns. Editing a city is UPDATE; adding a whole column is ALTER.
3 · Does SQL run top-to-bottom in the order you wrote the clauses?
The engine runs FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT. Because SELECT runs after WHERE, an alias you make in SELECT does not exist yet when WHERE runs.