The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Insert one rowINSERT INTO customers (name, email) VALUES ('Ada', 'ada@example.com');View examples
Insert several rowsINSERT INTO tags (name) VALUES ('sql'), ('database'), ('backend');View examples
Insert query resultsINSERT INTO customer_archive (id, name) SELECT id, name FROM customers WHERE inactive = true;View examples
Use a column defaultINSERT INTO jobs (name, status) VALUES ('reindex', DEFAULT);View examples
Update matching rowsUPDATE customers SET active = false WHERE last_seen_at < DATE '2025-01-01';View examples
Update from the old valueUPDATE products SET price = price * 1.05 WHERE category = 'books';View examples
Update from another tableUPDATE products AS p SET price = i.price FROM imports AS i WHERE i.sku = p.sku;View examples
Delete matching rowsDELETE FROM sessions WHERE expires_at < CURRENT_TIMESTAMP;View examples
Delete using another tableDELETE FROM cart_items AS ci USING products AS p WHERE p.id = ci.product_id AND p.discontinued = true;View examples
Ignore a duplicate insertINSERT INTO tags (name) VALUES ('sql') ON CONFLICT (name) DO NOTHING;View examples
Upsert a rowINSERT INTO counters (key, value) VALUES ('views', 1) ON CONFLICT (key) DO UPDATE SET value = counters.value + EXCLUDED.value;View examples
Return changed valuesINSERT INTO customers (name) VALUES ('Ada') RETURNING id, name;View examples
Begin a transactionBEGIN;View examples
Commit a transactionCOMMIT;View examples
Roll back a transactionROLLBACK;View examples
Create a savepointSAVEPOINT before_optional_step;View examples
Roll back to a savepointROLLBACK TO SAVEPOINT before_optional_step;View examples

Treat data changes as explicit, reviewable operations. Name inserted columns, test the predicates used by updates and deletes, return affected identifiers when useful, and group related statements in a transaction.

Step by step

Detailed examples

01

Insert explicit and query-derived rows

Name the destination columns so schema changes do not silently alter value placement. A VALUES list handles literal rows, INSERT SELECT copies query results, and DEFAULT requests the target column's configured default.

Insert one customer and several tags
INSERT INTO customers (name, email)
VALUES ('Ada', 'ada@example.com');

INSERT INTO tags (name)
VALUES ('sql'), ('database'), ('backend');
Archive selected customers
INSERT INTO customer_archive (id, name)
SELECT id, name
FROM customers
WHERE inactive = true;

INSERT INTO jobs (name, status)
VALUES ('reindex', DEFAULT);

Note: The selected expressions must align with the target columns by position and use compatible types.

Back to quick reference ↑
02

Update only reviewed target rows

An UPDATE without WHERE affects every row. First run a SELECT with the intended predicate, then reuse that predicate in the update. PostgreSQL's UPDATE FROM syntax can draw values from another table, but the join should produce at most one source row for each target.

Review and deactivate old customers
SELECT id, last_seen_at
FROM customers
WHERE last_seen_at < DATE '2025-01-01';

UPDATE customers
SET active = false
WHERE last_seen_at < DATE '2025-01-01';
Calculate prices and import replacements
UPDATE products
SET price = price * 1.05
WHERE category = 'books';

UPDATE products AS p
SET price = i.price
FROM imports AS i
WHERE i.sku = p.sku;

Note: UPDATE FROM is PostgreSQL syntax. Other database systems use different joined-update forms.

Back to quick reference ↑
03

Delete with a precise predicate

DELETE without WHERE removes every row from the target table. Preview the exact predicate with SELECT and use a transaction for important changes. PostgreSQL USING makes other tables available to the delete condition.

Remove expired sessions
SELECT id, expires_at
FROM sessions
WHERE expires_at < CURRENT_TIMESTAMP;

DELETE FROM sessions
WHERE expires_at < CURRENT_TIMESTAMP;
Remove cart items for discontinued products
DELETE FROM cart_items AS ci
USING products AS p
WHERE p.id = ci.product_id
  AND p.discontinued = true;

Note: Foreign-key actions, triggers, and permissions can affect or prevent a deletion. Review the schema before applying bulk changes.

Back to quick reference ↑
04

Handle unique conflicts intentionally

PostgreSQL ON CONFLICT can ignore a conflicting insert or update the existing row. Identify a valid unique constraint or index as the conflict target, and use EXCLUDED to access the values proposed by the insert.

Ignore duplicate tags
INSERT INTO tags (name)
VALUES ('sql')
ON CONFLICT (name) DO NOTHING;
Increment a named counter
INSERT INTO counters (key, value)
VALUES ('views', 1)
ON CONFLICT (key) DO UPDATE
SET value = counters.value + EXCLUDED.value;
Back to quick reference ↑
05

Return values from modified rows

PostgreSQL RETURNING avoids a second query when the caller needs generated identifiers or changed values. Its expression list works like a SELECT output list and can be attached to INSERT, UPDATE, or DELETE.

Return an inserted identifier
INSERT INTO customers (name, email)
VALUES ('Ada', 'ada@example.com')
RETURNING id, name, email;
Return updated rows
UPDATE jobs
SET status = 'running'
WHERE status = 'queued'
RETURNING id, name, status;
Back to quick reference ↑
06

Group related changes in a transaction

A transaction makes a sequence atomic: COMMIT keeps it and ROLLBACK discards it. Savepoints allow a partial rollback without abandoning earlier work, but they do not replace application error handling or appropriate isolation choices.

Transfer a balance atomically
BEGIN;

UPDATE accounts
SET balance = balance - 50
WHERE id = 1;

UPDATE accounts
SET balance = balance + 50
WHERE id = 2;

COMMIT;

Note: Real financial transfers also need constraints, row locking, sufficient-funds checks, and an appropriate transaction isolation level.

Undo an optional step
BEGIN;

UPDATE orders SET status = 'processing' WHERE id = 42;
SAVEPOINT before_optional_step;
INSERT INTO notifications (order_id, channel) VALUES (42, 'email');
ROLLBACK TO SAVEPOINT before_optional_step;

COMMIT;
Discard an entire transaction
BEGIN;
UPDATE products SET price = price * 2;
ROLLBACK;
Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. PostgreSQL Global Development GroupData Manipulationpostgresql.org
  2. PostgreSQL Global Development GroupINSERTpostgresql.org
  3. PostgreSQL Global Development GroupReturning Data from Modified Rowspostgresql.org
  4. PostgreSQL Global Development GroupTransactionspostgresql.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback