UPDATE: changing rows
In short: UPDATE … SET changes column values in the rows that WHERE selects, and without WHERE it changes every row in the table.
Problem
A price rise
The dairy supplier raises prices by 10%. From today the shop has to sell everything in the “Dairy” category 10% higher as well.
There are five products. You could change the prices by hand, one by one. But tomorrow it will be a category with 200 products, and copying by hand is sure to go wrong.
The idea
UPDATE … SET … WHERE
UPDATE says which table, SET says which column and what it becomes, and WHERE says in which rows:
price * 1.1 is worked out for each row separately, with that row's price. Fresh milk was 1.60 € and is now 1.76 €. ROUND(…, 2) rounds to the cent, because the price is in euros and cents. Above the result you can see how many rows the statement changed: five.
More precisely, if you are curious
Without ROUND the screen also shows 1.76. But for the computer 1.6 × 1.1 is 1.7600000000000002, because fractions are stored in binary and not always exactly. Then a search for the price 1.76 does not find the fresh milk:
So round money when you store it. Real shops often keep prices in whole cents (176) or in a column with an exact decimal type, which PostgreSQL and MySQL have (DECIMAL). SQLite has no such type.
SET can hold several columns, separated by commas. 30 banitsas arrive, and their price becomes 2.60 €:
stock + 30 takes the old stock and adds 30. In the expression to the right of =, the columns hold the old values of the row.
Try it
An order shipped
Order 59 is paid and went out with the courier today. Change its status to shipped.
Solution
UPDATE orders SET status = 'shipped' WHERE id = 59;UPDATE orders SET status = 'shipped' WHERE id = 59. The check looks at every paid and shipped order. That way it shows if you changed another order too.
See it
UPDATE without WHERE
The manager wants a promotion: mint tea for 0.99 €. Someone types in a hurry and forgets WHERE:
All 25 products now cost 0.99 €, even the knife set that was 39 €. The database does not ask “are you sure?”. Without WHERE the statement is for every row.
Here the “Fresh database” button fixes everything. A real database has no such button. What is left are backups and transactions: with a transaction a change can be undone before it is confirmed. You will meet them later in the course.
The idea
SELECT first
The habit that protects you from this: before an UPDATE, run a SELECT with the same WHERE. You see exactly which rows will change, and nothing changes.
Drinks go up by 5%. The category is known by name, and a subquery gives its number:
Four products, exactly the right ones. Now SELECT … FROM becomes UPDATE … SET, and WHERE stays the same:
Here ROUND makes a visible difference: 0.90 × 1.05 is 0.945, and 14.90 × 1.05 is 15.645. The prices become 0.95 € and 15.65 €.
A subquery in WHERE works in UPDATE just as it does in SELECT.
Try it
The forgotten orders
There are orders with the status new from before 2026 that nobody has paid. Cancel them: their status becomes cancelled.
Solution
UPDATE orders SET status = 'cancelled'
WHERE status = 'new' AND ordered_at < '2026-01-01';UPDATE orders SET status = 'cancelled' WHERE status = 'new' AND ordered_at < '2026-01-01'. Two orders, 4 and 10. If you run a SELECT with the same WHERE first, you will see exactly them.
Exercise
Two tasks
1. A promotion for the products the shop has plenty of: every product with more than 50 in stock gets 20% cheaper, rounded to the cent. The gift card has no category and is not part of the promotion.
The promotion (the whole products table is checked):
Solution
UPDATE products
SET price = ROUND(price * 0.8, 2)
WHERE stock > 50 AND category_id IS NOT NULL;UPDATE products SET price = ROUND(price * 0.8, 2) WHERE stock > 50 AND category_id IS NOT NULL. Five products: the butter roll, apples, potatoes, water and cleaning sponges. The butter roll becomes 0.64 €. Without the second condition the 20 € gift card would sell for 16 €.
2. Maria Ivanova (maria.ivanova@example.com) paid all her new orders at once. Change their status to paid. Find the customer by email, with a subquery.
Maria's new orders become paid:
Solution
UPDATE orders SET status = 'paid'
WHERE status = 'new'
AND customer_id = (SELECT id FROM customers WHERE email = 'maria.ivanova@example.com');UPDATE orders SET status = 'paid' WHERE status = 'new' AND customer_id = (SELECT id FROM customers WHERE email = 'maria.ivanova@example.com'). Orders 34 and 46. The email is unique, so the subquery returns exactly one customer.
Test
Check yourself
Related lessons
Section titled "Related lessons"- Builds on: NULL: no value · Arithmetic in a query · Subqueries · INSERT: new rows
- Continues in: DELETE: deleting rows · UPSERT: insert or update · Views · Normalization
- Tasks on this topic: Changing data