Deleting Data

1. Deleting Specific Rows

DELETE FROM customers WHERE id = 42;
Best PracticeWhy
WHERE PKMost efficient and safe
LIMIT via CTEBatch deletes to avoid long locks

2. Deleting All Rows

DELETE FROM staging;     -- row by row (slower, generates WAL)
TRUNCATE staging;        -- DDL, fast, also frees space

3. Deleting with Subquery

DELETE FROM orders
 WHERE customer_id IN (SELECT id FROM customers WHERE status='deactivated');
WITH del_orders AS (
   DELETE FROM orders WHERE customer_id = 42 RETURNING id
)
DELETE FROM order_items WHERE order_id IN (SELECT id FROM del_orders);

5. Using RETURNING Clause

DELETE FROM events WHERE created_at < now() - interval '90 days'
RETURNING id, created_at;
UsePattern
Audit logInsert RETURNING row into archive
Cascading workFeed CTE for downstream updates

6. Deleting with JOIN

DELETE FROM orders o
 USING customers c
 WHERE o.customer_id = c.id AND c.status = 'deactivated';
Note: PostgreSQL uses USING (not JOIN) for multi-table DELETE.

7. Truncating Table

TRUNCATE TABLE staging;
vs DELETETRUNCATE
SpeedO(1) (drops files, no row scan)
TriggersFires TRUNCATE triggers only
LockACCESS EXCLUSIVE
BloatReleases space immediately

8. Truncating Multiple Tables

TRUNCATE orders, order_items;

9. Truncating with CASCADE

TRUNCATE customers RESTART IDENTITY CASCADE;
BehaviorEffect
CASCADEAuto-truncate FK-referencing tables
RESTRICTDefault; error if FKs exist

10. Restarting Identity Sequences

TRUNCATE orders RESTART IDENTITY;
-- Or manually
SELECT setval(pg_get_serial_sequence('orders','id'), 1, false);
OptionBehavior
RESTART IDENTITYReset sequences to starting value
CONTINUE IDENTITYDefault; keep last allocated value