Copied to Clipboard
You do not have to list id or created_at if the table fills those in for you (more on that in Part 08). You only name the columns you care about.
Insert many rows at once
You do not need one statement per row. Stack them up, separated by commas:
INSERT INTO users (name, email, country)
VALUES
('Omar', 'omar@example.com', 'EG'),
('Lina', 'lina@example.com', 'SA'),
('Noah', 'noah@example.com', 'US');
One trip to the database, three new users. Faster and cleaner than three separate inserts.
Getting the new id back (Postgres)
Here is a problem you will hit in real web apps. A user signs up, you INSERT them, and now you want their new id so you can log them in or create their first order. How do you find out the id the database just made?
In Postgres, you ask for it with RETURNING:
INSERT INTO users (name, email, country)
VALUES ('Sara', 'sara@example.com', 'EG')
RETURNING id;
The database hands you back the fresh id right away. No second query needed. This is one of those small things you will use constantly once you know it exists.
UPDATE: changing a page
UPDATE picks rows and changes some of their columns. It looks like this:
UPDATE users
SET country = 'EG'
WHERE id = 5;
Read it in plain English: "find the user whose id is 5, and set their country to EG." That WHERE id = 5 is the most important line in the whole query.
The horror story
Now look at the exact same query with one line missing:
-- DO NOT run this for real
UPDATE users
SET country = 'EG';
No WHERE. So this does not change one user. It changes every user in the table to country EG. Your one customer in the US, your three in Saudi Arabia, all of them, gone, now all EG. This is the pen scribbling over every page.
There is no Ctrl+Z. The data is just... different now. People have lost their jobs over a missing WHERE. We will fix this habit in a minute.
DELETE: tearing out a page
DELETE removes whole rows.
DELETE FROM orders
WHERE id = 42;
That deletes one order. Fine. But you already see where this is going:
-- DO NOT run this for real
DELETE FROM orders;
No WHERE, so this empties the entire orders table. Every order, gone. Same horror, different verb.
The one habit that saves you
Before you run any UPDATE or DELETE, run a SELECT with the exact same WHERE first. Look at what comes back. Those rows are the ones you are about to change.
-- Step 1: look before you leap
SELECT * FROM users WHERE country = 'EG' AND created_at < '2020-01-01';
-- Step 2: same WHERE, now do the change
UPDATE users
SET status = 'inactive'
WHERE country = 'EG' AND created_at < '2020-01-01';
If Step 1 returns 3 rows, you know Step 2 will touch 3 rows. If Step 1 returns 90,000 rows, stop and think. This tiny habit catches almost every disaster before it happens.
There is also a bigger safety net coming. In Part 12 you will meet transactions, where you can run a change, look at the result, and type ROLLBACK to undo it if it looks wrong. Like a pencil after all, for a short moment. For now, the SELECT-first habit is your seatbelt.
Bonus: create or update in one go (UPSERT)
Sometimes you want "insert this row, but if it already exists, just update it." That is an UPSERT. In Postgres:
INSERT INTO users (email, name)
VALUES ('sara@example.com', 'Sara')
ON CONFLICT (email) DO UPDATE
SET name = EXCLUDED.name;
If the email is new, it inserts. If that email already exists, it updates the name instead of crashing. Handy for "save my profile" buttons. You do not need to master this today, just know the phrase ON CONFLICT exists.
Gotchas juniors hit
-
Forgetting WHERE. The big one. No WHERE on UPDATE or DELETE means "all rows". Always ask: "did I scope this?"
-
Running before looking. Skipping the SELECT-first habit because you are "sure". You are not sure. Look anyway.
-
Confusing UPDATE and INSERT. UPDATE changes rows that exist. INSERT makes new ones. If you UPDATE a user that is not there, nothing happens (zero rows changed), and you might not notice.
Recap
-
INSERT INTO table (cols) VALUES (...) adds rows. You can add many at once.
-
RETURNING id (Postgres) hands you the new id right after an insert.
-
UPDATE ... SET ... WHERE ... changes rows. DELETE FROM ... WHERE ... removes them.
- A missing
WHERE hits every row. That is the pen scribbling over every page.
- Always run a
SELECT with the same WHERE first. Transactions (Part 12) let you ROLLBACK.
Your turn
Picture the orders table. You want to delete every order with status 'cancelled'. Before you write the DELETE, write the SELECT you would run first to see what you are about to remove. If you can explain why that SELECT keeps you safe, you have got the most important habit in this whole post.
Next up, Part 08: Designing Tables, Data Types and Constraints, where you learn how those tables get built and how the database can stop bad data before it ever gets in.