Update Existing Rows in Tables
Learn how to update existing rows in PostgreSQL tables with practical examples, troubleshooting tips, and next steps in the tutorial track.
Focus: update existing rows in tables
Updating data is where a database earns its keep — but it’s also where careless SQL can silently corrupt hours of work. Whether you’re fixing a typo in a user profile, adjusting a price, or migrating a status field across millions of rows, the UPDATE statement is your scalpel. In this lesson, you’ll learn to wield it precisely: how to construct safe updates, avoid common foot-guns, and decide between row-level edits and bulk strategies. By the end, you’ll not just know the syntax — you’ll trust your updates.
The problem this lesson solves
You’ve inserted data into your tables — users, orders, products. But the world isn’t static. Emails change, stock levels fluctuate, and your boss just asked you to apply a 10% discount to all items in the "clearance" category. Without a solid grasp of updating existing rows, you’re stuck re-inserting records (bad idea) or running risky blanket updates that could nuke your data.
The UPDATE statement is how you modify one or more existing rows in a PostgreSQL table. It’s a core part of the CRUD toolkit (Create, Read, Update, Delete), and it’s something you’ll use daily in real applications. The pain: a single mistyped WHERE clause can update thousands of rows you never intended to touch. This lesson shows you how to update with confidence — using precise conditions, safe patterns, and sanity checks.
Core concept / mental model
Think of a table as a spreadsheet, and UPDATE as editing specific cells in specific rows. You always specify which rows to change (the WHERE clause) and what to change (the SET clause). If you forget the WHERE, you’ve just edited every row in the table — like changing every cell in a column without meaning to.
Here’s the mental model in SQL terms:
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
- The
SETclause defines new values for one or more columns. - The
WHEREclause filters which rows get updated. If omitted, all rows are updated. - PostgreSQL evaluates the
WHEREcondition per row, and only rows that match are changed.
It’s also helpful to think about atomicity: an UPDATE runs as a single transaction by default. Either it succeeds entirely, or it rolls back if something fails. You won’t end up with half-updated rows — that’s a key safety net.
How it works step by step
Let’s break down the update process logically:
- Identify the table you want to modify.
- Decide which columns need new values (the
SETclause). - Write the
WHEREcondition to target exactly the rows you want. This is the most critical step — test it with aSELECTfirst if you’re unsure. - Execute the update. PostgreSQL locks the affected rows for the duration — others will see the old version until you commit (if inside a transaction).
- Verify the results by running a
SELECTto confirm the changes.
The order matters: you’re not inserting new rows, but altering existing ones. Unlike INSERT (which adds), UPDATE preserves the row identity — primary keys stay the same, and any indexes are updated automatically.
Hands-on walkthrough
Let’s get our hands dirty. We’ll start with a sample products table to see how updates work in practice.
-- Create a sample table
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
category TEXT,
price NUMERIC(10,2),
in_stock BOOLEAN DEFAULT true
);
-- Insert some data
INSERT INTO products (name, category, price, in_stock) VALUES
('Widget', 'Gadgets', 19.99, true),
('Gadget Pro', 'Gadgets', 49.99, true),
('Thingamajig', 'Gadgets', 29.99, false),
('Doodad', 'Gizmos', 9.99, true);
Now, let’s update a single row — change the price of the 'Widget' to 24.99:
UPDATE products
SET price = 24.99
WHERE name = 'Widget';
To check what changed:
SELECT * FROM products WHERE name = 'Widget';
Expected output:
id | name | category | price | in_stock
----+--------+----------+-------+----------
1 | Widget | Gadgets | 24.99 | t
Now update multiple columns at once — set the 'Thingamajig' to be in stock and apply a discount:
UPDATE products
SET in_stock = true, price = price * 0.9
WHERE id = 3;
Notice you can reference the existing column value in the expression — price * 0.9 uses the current price.
Expected output:
UPDATE 1
That UPDATE 1 means one row was affected — a quick sanity check.
Compare options / when to choose what
There’s more than one way to update data. Here’s a comparison of common approaches:
| Method | Use case | Pros | Cons |
|---|---|---|---|
Simple UPDATE with WHERE |
Single or few rows | Precise, readable | Must be careful with conditions |
UPDATE with subquery |
Values derived from other tables | Powerful, avoids multiple queries | Can be complex, harder to debug |
UPDATE ... FROM |
Joining another table for matching | Efficient for bulk updates | Syntax can be confusing |
INSERT ... ON CONFLICT DO UPDATE |
Upsert (insert or update) | Handles both insert and update | Not for updating existing rows only |
For most day-to-day updates, a simple UPDATE with WHERE suffices. Use a subquery when the new value depends on data from another table. For bulk updates joining multiple tables, UPDATE ... FROM is your friend. If you need to insert or update based on existence, consider upsert.
Troubleshooting & edge cases
Forgetting the WHERE clause
The classic disaster: running UPDATE products SET in_stock = true; updates every row. Always test your WHERE with a SELECT first:
-- Test the condition
SELECT * FROM products WHERE category = 'Gadgets';
-- Then update
UPDATE products SET in_stock = true WHERE category = 'Gadgets';
Condition matches nothing
If your WHERE matches zero rows, PostgreSQL simply returns UPDATE 0 — no error. This can be confusing; it’s often a typo in the condition. Double-check your values and the actual data in the table.
Data type mismatches
Updating a numeric column with a string will raise an error like invalid input syntax for type numeric. Ensure the new value’s type matches the column’s type, or cast explicitly: SET price = '24.99'::numeric.
Concurrency issues
If two transactions update the same row simultaneously, PostgreSQL uses row-level locking. The second update will wait until the first commits. If you don’t want to wait, you can use NOWAIT or handle lock timeouts in your application.
What you learned & what's next
You’ve mastered the core of updating existing rows in tables: you can now craft precise UPDATE statements, update multiple columns in one go, and avoid the infamous WHERE-less wipe-out. You also understand when to use simple updates versus subqueries or upserts.
This is a key milestone in your PostgreSQL journey — you’re no longer just inserting static data; you’re dynamically maintaining it. Next up, you’ll learn how to delete rows safely with DELETE, and later, how to combine INSERT, UPDATE, and DELETE in transactions for robust data operations.
Keep practicing, and always remember: with great update power comes great responsibility.
Practice recap
Try this: create a small table of your own (e.g., tasks with status and due_date). Insert a few rows, then practice updating a single row, updating multiple rows based on a condition, and updating a column using an expression. Always run a SELECT to verify before and after. This will cement the habits that keep your data safe.
Common mistakes
- Forgetting the WHERE clause and updating all rows in the table — always test your condition with a SELECT first.
- Using a non-unique column in the WHERE clause (like name) and accidentally updating multiple rows you intended to be unique.
- Assuming UPDATE 0 means an error — it just means no rows matched; verify your condition against the actual data.
- Trying to update a column to a value of the wrong data type without casting, causing a type mismatch error.
- Updating in a loop from application code instead of using a single set-based UPDATE — slow and error-prone.
Variations
- Use UPDATE ... FROM to join another table and set values based on matching rows — efficient for bulk edits.
- Use INSERT ... ON CONFLICT DO UPDATE (upsert) when you want to insert new rows or update existing ones in one statement.
- Use a subquery in the SET clause to compute new values from other tables or aggregates.
Real-world use cases
- A user changes their email address: UPDATE users SET email = 'new@example.com' WHERE id = 123;
- A price increase of 5% for all items in a category: UPDATE products SET price = price * 1.05 WHERE category = 'Electronics';
- Marking all orders older than 30 days as 'shipped': UPDATE orders SET status = 'shipped' WHERE order_date < now() - interval '30 days';
Key takeaways
- The UPDATE statement modifies existing rows with SET for new values and WHERE to filter which rows.
- Always include a precise WHERE clause — omitting it updates every row in the table.
- You can reference the current column value in an expression to compute new ones (e.g., price * 1.1).
- Test your WHERE condition with SELECT before executing an UPDATE to avoid disaster.
- UPDATE operations are atomic and lock rows for consistency in concurrent environments.
- Know when to use simple UPDATE vs. UPDATE...FROM vs. upsert for different scenarios.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.