How to Update and Delete Data in PostgreSQL (Guide)
Learn how to update data in PostgreSQL and delete rows safely, with copy-pasteable UPDATE and DELETE examples explained line by line for beginners.
Learn how to update data in PostgreSQL and delete rows safely, with copy-pasteable UPDATE and DELETE examples explained line by line for beginners.
If you searched for how to update data in PostgreSQL, here is the short answer: you use the UPDATE statement to change existing rows, and the DELETE statement to remove rows you no longer need. Both commands work with a WHERE clause that tells PostgreSQL exactly which rows to touch. Get the WHERE clause wrong (or forget it) and you can change or delete every row in the table by accident.
This guide walks through both statements from scratch. You do not need any prior experience with UPDATE or DELETE, but it helps if you already know how to create a table and insert rows. If you are new to that, read our guides on how to create a table in PostgreSQL and how to insert data into a PostgreSQL table first, then come back here.
Every example below uses a simple table called customers. Run this in psql or pgAdmin to follow along. A table is just a grid of rows and columns, like a spreadsheet, and SERIAL PRIMARY KEY means id will fill itself in automatically with a unique number for each row.
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
city TEXT,
is_active BOOLEAN DEFAULT true
);
INSERT INTO customers (name, email, city, is_active) VALUES
('Amara Okafor', 'amara@example.com', 'Lagos', true),
('Liu Wei', 'liu@example.com', 'Austin', true),
('Sofia Rossi', 'sofia@example.com', 'Milan', false);CREATE TABLE sets up the columns and their data types: TEXT for words, BOOLEAN for true/false. INSERT INTO then adds three sample rows in one go, listing the columns first and the matching values after VALUES. Each row is wrapped in its own parentheses and separated by a comma.
UPDATE changes the values in existing rows. The basic shape is: UPDATE table_name SET column = new_value WHERE condition. The WHERE part is what limits the change to specific rows, so read it carefully every time.
UPDATE customers
SET city = 'Chicago'
WHERE id = 2;Line by line: UPDATE customers tells PostgreSQL which table to change. SET city = 'Chicago' says which column to change and what to put in it. WHERE id = 2 limits the change to the one row where id equals 2, so only Liu Wei's city moves to Chicago, not every customer's.
You can update more than one column at once by separating them with commas, and PostgreSQL will apply all the changes to the matching rows at the same time.
UPDATE customers
SET city = 'Boston', is_active = true
WHERE email = 'sofia@example.com';This finds the row where email matches sofia@example.com and updates both city and is_active in a single statement. Matching on email works here because email values are unique, so exactly one row changes.
If you leave out WHERE entirely, PostgreSQL updates every single row in the table, not just the one you meant.
-- Danger: this changes the city for ALL customers, not one
UPDATE customers
SET city = 'Chicago';Because there is no WHERE clause, PostgreSQL has no reason to skip any row, so every customer's city becomes Chicago. Always add a WHERE clause when you update, unless changing every row really is what you want.
Before you run an UPDATE or DELETE, run the same WHERE condition inside a SELECT statement first. This shows you exactly which rows will be affected, with zero risk, before you commit to the change.
SELECT id, name, city
FROM customers
WHERE city = 'Austin';This lists every row where city equals Austin, so you can check the row count and the names before you touch anything. If you are new to SELECT and WHERE, our SQL SELECT and WHERE guide covers the basics in more depth.
Want a refresher on filtering rows before you write an UPDATE or DELETE?
Read the SELECT and WHERE guideDELETE removes whole rows from a table. The shape is similar to UPDATE: DELETE FROM table_name WHERE condition. There is no SET clause, because you are not changing values, you are removing the row entirely.
DELETE FROM customers
WHERE is_active = false;DELETE FROM customers targets the customers table. WHERE is_active = false limits the deletion to rows where that column is false. Only rows matching the condition are removed; every other row stays exactly as it was.
Just like UPDATE, leaving out WHERE is dangerous: DELETE FROM customers on its own would remove every row in the table, leaving it empty but still existing (the table structure stays, only the data is gone).
PostgreSQL has a feature many other databases lack: you can add RETURNING to an UPDATE or DELETE to see the affected rows immediately, without running a separate SELECT.
UPDATE customers
SET is_active = true
WHERE id = 3
RETURNING id, name, is_active;This updates the row where id is 3, then RETURNING id, name, is_active prints those three columns for the row that was just changed, so you can confirm the update worked without a follow-up query.
| Situation | Statement to use |
|---|---|
| A customer moved to a new city | UPDATE, change the city column |
| A customer closed their account | UPDATE, set is_active to false (keeps their history) |
| Duplicate row entered by mistake | DELETE, remove the extra row |
| Test data you no longer need | DELETE, remove those rows |
| You are not sure yet | SELECT first, then decide |
In real applications, teams often prefer UPDATE over DELETE for things like closed accounts, because it keeps the history instead of erasing it. Save DELETE for data you genuinely want gone, like duplicates or test rows.
A transaction lets you try a change and cancel it if something looks wrong, before it becomes permanent. Wrap your UPDATE or DELETE between BEGIN and COMMIT, and you get a chance to check the result first.
BEGIN;
UPDATE customers
SET city = 'Denver'
WHERE id = 1;
SELECT id, name, city FROM customers WHERE id = 1;
-- Looks correct, so make it permanent:
COMMIT;
-- If it looked wrong, you would run ROLLBACK; instead of COMMIT;BEGIN starts the transaction, so nothing is final yet. The UPDATE runs as normal, and the SELECT right after lets you check the new value while you can still change your mind. COMMIT saves the change permanently. If the SELECT had shown something unexpected, running ROLLBACK instead would undo the UPDATE completely, as if it never happened.
PostgreSQL updates every row in the table, not just one. There is no built-in warning before this happens, so always double-check your WHERE clause, or run the same condition as a SELECT first to preview it.
Only if you ran it inside a transaction and have not typed COMMIT yet, in which case ROLLBACK will undo it. Once a DELETE is committed, the data is gone unless you have a backup, so previewing with SELECT first is the safest habit.
DELETE removes rows one at a time and can use a WHERE clause to target specific rows. TRUNCATE empties the entire table at once and cannot be filtered with WHERE, so it is only useful when you want every row gone.
No, RETURNING is optional. It is useful when you want to see the changed rows immediately, such as in an application that needs to show the updated data right after saving it, but plain UPDATE and DELETE work fine without it.
For things like user accounts or orders, marking a row inactive with UPDATE usually beats deleting it, because you keep the history and can restore it later. Save DELETE for genuine mistakes, duplicates, or temporary test data.
New to PostgreSQL? Start from the beginning with our guide to inserting your first rows.
Read the INSERT guideWant help building a real application on top of PostgreSQL?
Talk to FepiqOccasional, no-fluff notes on shipping modern software — startups, automation, Laravel, Shopify and more. No spam, unsubscribe anytime.
Keep reading
What is an index in SQL? A plain-English guide with copy-paste examples showing how indexes speed up queries and when you actually need one.
Learn JavaScript DOM manipulation for beginners: select elements, change text and styles, and handle clicks with simple, copy-paste code examples.
Let's build something
Book a free discovery call. We'll listen, ask sharp questions, and send you a proposal within 3 business days.