Data modification & MERGE
Concept  ·  SQL & Querying

A multi-statement batch's partial-failure visibility depends on the transaction boundary.

Batch jobs are multiple statements pretending to be one change — debit here, credit there; delete-then-reload — and without a transaction the pretense fails exactly when statements do: a mid-batch error leaves the halfway state published, which is how a reload failure becomes an empty table in production. BEGIN/COMMIT makes the batch a unit; errors → ROLLBACK → the world never saw the attempt.

See it break
ledger
itemn
cola3
The trap
DELETE FROM ledger;

SELECT
  COUNT(*) AS rows
FROM
  ledger;
The fix
BEGIN;

DELETE FROM ledger;

ROLLBACK;

SELECT
  COUNT(*) AS rows
FROM
  ledger;
The trap
0
The fix
1

The bare delete-then-reload published a half state — a DELETE outside a transaction commits immediately, so a failed reload leaves the table empty; wrapping the batch in BEGIN ... ROLLBACK unhappens the attempt and the table keeps its pre-batch rows.

The rule

Transaction around any multi-statement invariant; delete-and-reload always inside one (or build-aside-and-swap); idempotency as the second seatbelt for the retry.

DDL-in-transaction support varies; some warehouses auto-commit per statement — know yours.

Shows up elsewhere
Idempotent upsertDELETE / UPDATE with joins
Try one →Prove it in practice →