UPDATE
Changes column values in the rows that match a condition.
Syntax
UPDATE table [AS t]
SET col1 = expr1, col2 = expr2
[FROM other_table]
[WHERE condition]
[RETURNING ...];- Without
WHERE, every row is updated. Run the sameWHEREas aSELECTfirst to see which rows will change, and use a transaction when in doubt. - Expressions on the right see the old values of the row:
SET a = b, b = aswaps them. UPDATE ... FROM otherjoins another table to compute new values or restrict rows. Each target row should match at most one row ofother; if several match, one is used unpredictably.SET col = DEFAULTrestores the default;SET col = NULLclears it.- Constraints are checked: a CHECK or foreign-key violation aborts the whole statement.
RETURNINGshows the updated rows; in PostgreSQL 18RETURNING old.col, new.colshows before and after.
Examples
UPDATE products
SET price = round(price * 1.05, 2)
WHERE category = 'Kitchen'
RETURNING product_id, product_name, old.price AS old_price, new.price AS new_price;Only Kitchen products change; RETURNING old/new (PostgreSQL 18) shows before and after.
UPDATE products p
SET stock = p.stock - s.units
FROM (SELECT product_id, sum(quantity) AS units
FROM orders WHERE status = 'processing'
GROUP BY product_id) s
WHERE s.product_id = p.product_id
AND p.stock >= s.units
RETURNING p.product_id, p.stock;Aggregate first so each product matches exactly one row of s.
Pitfalls
Forgetting WHERE (updates every row).
UPDATE ... FROM where the joined table has several matching rows per target row (non-deterministic result).
Comparing with = NULL in the WHERE clause (matches nothing).
Repeating the target table in FROM (UPDATE t ... FROM t creates a self-join over every row).
Other databases
For orientation only: SQL Quest executes PostgreSQL.
- SQL Server
UPDATE t SET ... FROM t JOIN other ...; OUTPUT deleted.col, inserted.col for before/after.
- MySQL
Multi-table form: UPDATE t JOIN other ON ... SET ...; supports ORDER BY and LIMIT on single-table UPDATE.