Lab 13: UPDATE and DELETE

Time: 30 minutes | Level: Foundations | DB: MySQL 8 / PostgreSQL 15

Overview

Master UPDATE with and without JOIN, DELETE with subquery, TRUNCATE vs DELETE differences, and the soft delete pattern with deleted_at timestamps.


Step 1: Setup

docker run -d --name mysql-lab -e MYSQL_ROOT_PASSWORD=rootpass mysql:8.0
for i in $(seq 1 30); do docker exec mysql-lab mysql -uroot -prootpass -e "SELECT 1" 2>/dev/null && break || sleep 2; done

docker exec mysql-lab mysql -uroot -prootpass << 'EOF'
CREATE DATABASE updatelab;
USE updatelab;

CREATE TABLE employees (
    emp_id      INT NOT NULL AUTO_INCREMENT,
    name        VARCHAR(100) NOT NULL,
    dept        VARCHAR(50) NOT NULL,
    salary      DECIMAL(10,2) NOT NULL,
    status      VARCHAR(20) DEFAULT 'active',
    deleted_at  TIMESTAMP NULL DEFAULT NULL,  -- for soft delete
    updated_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (emp_id)
);

CREATE TABLE departments (
    dept_id   INT NOT NULL AUTO_INCREMENT,
    dept_name VARCHAR(50) NOT NULL,
    bonus_pct DECIMAL(5,2) DEFAULT 0,
    PRIMARY KEY (dept_id)
);

INSERT INTO departments (dept_name, bonus_pct) VALUES
('Engineering', 10.0), ('Marketing', 7.5), ('HR', 5.0), ('Finance', 8.0);

INSERT INTO employees (name, dept, salary) VALUES
('Alice Johnson',  'Engineering', 95000),
('Bob Smith',      'Marketing',   72000),
('Carol Davis',    'Engineering', 110000),
('David Wilson',   'HR',          65000),
('Eve Martinez',   'Engineering', 98000),
('Frank Anderson', 'Marketing',   68000),
('Grace Taylor',   'HR',          70000),
('Henry Thomas',   'Engineering', 125000),
('Isabel Jackson', 'Finance',     88000),
('Jack White',     'Finance',     92000);
EOF

Step 2: Basic UPDATE

📸 Verified Output:

⚠️ ALWAYS include a WHERE clause with UPDATE. Without it, every row in the table gets updated! Run SELECT ... WHERE condition first to verify which rows you'll affect before running UPDATE.


Step 3: UPDATE with Expression

📸 Verified Output (after 10% raise):


Step 4: UPDATE with JOIN

📸 Verified Output:

PostgreSQL equivalent:

💡 MySQL uses UPDATE t1 JOIN t2 SET ... syntax. PostgreSQL uses UPDATE t1 SET ... FROM t2 WHERE .... Both achieve the same result.


Step 5: Basic DELETE

📸 Verified Output:


Step 6: DELETE with Subquery

📸 Verified Output:


Step 7: TRUNCATE vs DELETE

Feature
DELETE
TRUNCATE

WHERE clause

Yes

No

Speed on large tables

Slow

Very fast

Triggers fire

Yes

No (MySQL)

Resets AUTO_INCREMENT

No

Yes

Can ROLLBACK

Yes

No (MySQL) / Yes (PG)

Logs each row

Yes

Minimal

📸 Verified Output:


Step 8: Capstone — Soft Delete Pattern

Hard deletes destroy data permanently. The soft delete pattern marks rows as deleted without removing them.

📸 Verified Output:

💡 Soft delete benefits: Audit trail, easy restore, foreign key integrity preserved, "recycle bin" UX. Downsides: All queries need WHERE deleted_at IS NULL, index on deleted_at needed, storage grows. Most production apps use soft delete for important records.

Cleanup:


Summary

Operation
Syntax
Notes

Update one row

UPDATE t SET col=val WHERE id=x

Always use WHERE

Update all rows

UPDATE t SET col=val

Dangerous!

Update with expression

UPDATE t SET salary = salary * 1.1 WHERE ...

Computed updates

Update with JOIN (MySQL)

UPDATE t1 JOIN t2 ON ... SET t1.col = ...

Cross-table update

Update with FROM (PG)

UPDATE t1 SET col = t2.val FROM t2 WHERE ...

PG syntax

Delete specific rows

DELETE FROM t WHERE condition

Always use WHERE

Delete with subquery

DELETE FROM t WHERE id IN (SELECT ...)

Derived table in MySQL

Truncate

TRUNCATE TABLE t

Fast, irreversible in MySQL

Soft delete

UPDATE t SET deleted_at = NOW() WHERE id = x

Keep data, hide it

Next: Lab 14 — Transactions

Last updated