UPDATE changes column values in existing rows; DELETE removes rows. Both touch every row the WHERE matches — which is all of them if you forget it.
UPDATE
-- 10% raise for Sales; several columns can change at once
UPDATE employees
SET salary = salary * 1.10,
email = COALESCE(email, lower(name) || '@corp.in')
WHERE dept_id = 2;
SELECT emp_id, name, email, salary FROM employees WHERE dept_id = 2 ORDER BY emp_id;emp_id | name | email | salary
-------+-------+---------------+-------------------
5 | Priya | priya@corp.in | 121000.00000000001
6 | Arjun | arjun@corp.in | 77000
7 | Neha | neha@corp.in | 79200UPDATE using another table
-- raise everyone located in Hyderabad by 5000: subquery form (works everywhere)
UPDATE employees
SET salary = salary + 5000
WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = 'Hyderabad');
SELECT name, salary FROM employees WHERE dept_id = 3 ORDER BY emp_id;name | salary
-------+-------
Vikram | 85000
Sara | 90000-- UPDATE … FROM (PostgreSQL, SQLite 3.33+): join the table being updated
CREATE TABLE raises (emp_id INTEGER PRIMARY KEY, pct INTEGER);
INSERT INTO raises VALUES (3, 10), (4, 20);
UPDATE employees
SET salary = salary + salary * r.pct / 100
FROM raises AS r
WHERE r.emp_id = employees.emp_id;
SELECT name, salary FROM employees WHERE emp_id IN (3, 4) ORDER BY emp_id;name | salary
------+-------
Meera | 104500
Karan | 114000-- MySQL: multi-table UPDATE with JOIN
UPDATE employees e
JOIN raises r ON r.emp_id = e.emp_id
SET e.salary = e.salary + e.salary * r.pct / 100;
-- SQL Server: UPDATE … FROM with an alias
UPDATE e SET e.salary = e.salary + e.salary * r.pct / 100
FROM employees e JOIN raises r ON r.emp_id = e.emp_id;DELETE
-- remove order lines of cancelled orders, then the orders themselves
DELETE FROM order_items
WHERE order_id IN (SELECT order_id FROM orders WHERE status = 'cancelled');
DELETE FROM orders WHERE status = 'cancelled'
RETURNING order_id, customer_id;
SELECT COUNT(*) AS orders_left FROM orders;order_id | customer_id
---------+------------
105 | 4
orders_left
-----------
7The child rows (order_items) had to go first — otherwise the foreign key would block deleting the order (unless it was declared ON DELETE CASCADE).
Safe habits
Preview
Run
SELECT … WHERE <same condition>first and check the row count.Wrap in a transaction
BEGIN; UPDATE …;→ check the result →COMMITorROLLBACK.Limit the blast radius
Key the
WHEREon the primary key when you mean one row.Prefer soft deletes for business data
UPDATE … SET deleted_at = CURRENT_TIMESTAMPkeeps history and is reversible.
BEGIN;
UPDATE employees SET salary = 1; -- oops: no WHERE, all 10 rows changed
SELECT COUNT(*) AS paid_one_rupee FROM employees WHERE salary = 1;
ROLLBACK; -- undo everything since BEGIN
SELECT name, salary FROM employees WHERE emp_id = 1;paid_one_rupee
--------------
10
name | salary
-----+-------
Asha | 150000How do you delete rows from one table based on another table?
What happens if you run UPDATE without WHERE?