Lakehouse Digest
ISSUE 012 · SEPTEMBER 30, 2026

Your INSERT OVERWRITE just deleted data you never touched

INSERT OVERWRITE defaults to static mode: without a PARTITION clause it truncates all table data — not just the partitions your source touches. The legacy dynamic-mode escape hatch is not supported on SQL warehouses or serverless. The compute-independent fix is REPLACE USING — key-equality, atomic, safe on empty sources.

THE THREE-PART READ

Catch the wipe. Pick the replacement. Keep the recovery ready.

A practical runbook for partition-scoped replacements that must behave the same on clusters, SQL warehouses, and serverless.

TIP · REPRODUCIBLE

Static mode wipes the table

Run a one-day refresh and watch prior partitions disappear under the documented default.

See the example →
IMPLEMENTATION · VERSIONED

Pick from the modern menu

Compare REPLACE WHERE, REPLACE USING, REPLACE ON, and the legacy dynamic-mode setting.

Choose safely →
DEV Q&A · MIGRATION

Why the warehouse wiped it

The cluster-only session setting vanished at migration time. Replace it with one compute-independent statement.

Get the answer →

Last verified against official Databricks docs: September 30, 2026. Correction history: Sep 30, 2026 — added the missing staging_daily setup with before/after results; replaced undocumented “silently ignored” with “not supported”; qualified wipe claims with the no-PARTITION-clause condition.

Reproducible example — setup

CREATE OR REPLACE TABLE main.default.daily_sales (
  sale_id INT, dt DATE, amount DECIMAL(10,2)
) PARTITIONED BY (dt);

INSERT INTO main.default.daily_sales VALUES
  (1, DATE '2026-09-28', 120.00),
  (2, DATE '2026-09-29',  85.50),
  (3, DATE '2026-09-29',  41.00);

CREATE OR REPLACE TEMP VIEW staging_daily AS
SELECT 4 AS sale_id,
       DATE '2026-09-30' AS dt,
       CAST(99.00 AS DECIMAL(10,2)) AS amount;

Before

SELECT sale_id, dt, amount
FROM main.default.daily_sales
ORDER BY dt, sale_id;
Expected output — 3 rows: (1, 2026-09-28, 120.00), (2, 2026-09-29, 85.50), (3, 2026-09-29, 41.00).

The daily job, whose source holds only 2026-09-30 rows

INSERT OVERWRITE TABLE main.default.daily_sales
SELECT * FROM staging_daily WHERE dt = DATE '2026-09-30';

After

SELECT sale_id, dt, amount
FROM main.default.daily_sales
ORDER BY dt, sale_id;
Expected output — 1 row: (4, 2026-09-30, 99.00).
Expected result: only the 2026-09-30 rows remain — the 09-28 and 09-29 rows are gone. That is the documented default static-mode behavior, not a bug: an unqualified static overwrite replaces all table data unless dynamic mode is enabled.

The fix

INSERT INTO main.default.daily_sales
REPLACE USING (dt)
SELECT * FROM staging_daily;

This replaces only rows whose dt matches a dt present in the source, leaves every other row untouched, inserts rows with new keys, and — unlike REPLACE WHERE — deletes nothing when the source is empty. On DBR 16.3–17.1 the USING list must contain the full set of the table's partition columns; on 17.2+ any columns work, on partitioned, unpartitioned, or liquid-clustered tables.

  1. Know your runtime's menu: SQL REPLACE WHERE 12.2+, REPLACE USING 16.3+ (full dynamic overwrite 17.2+), REPLACE ON 17.1+.
  2. On 16.3–17.1, USING must name the full partition-column set.
  3. Before running, list the source's distinct replacement keys: SELECT DISTINCT dt FROM staging_daily — confirm they are the partitions you intend to touch.
  4. Never trust REPLACE WHERE with a possibly-empty source; REPLACE USING/ON are safe.
  5. On any compute migration (classic → serverless/SQL warehouse), re-audit every SET spark.sql.sources.partitionOverwriteMode job — in SQL it is classic-compute-only and not supported elsewhere.
  6. Keep RESTORE ready: note the table version before the overwrite.

Use this when

  • Key-based daily replacements (REPLACE USING, 17.2+).
  • REPLACE USING on 16.3–17.1 when USING names all partition columns.
  • Fixed one-shot predicate replacements (REPLACE WHERE).
  • NULL-safe or complex matching (REPLACE ON).

Avoid this when

  • Starting a new workload that needs partition-scoped overwrites — use the modern options, not the legacy mode.
  • Relying on the SET in SQL on warehouses/serverless (not supported).
  • Combining replaceUsing/replaceOn with replaceWhere/partitionOverwriteMode/overwriteSchema in one writer.
  • Using REPLACE WHERE with a possibly-empty source.
My daily overwrite ran fine for months on an all-purpose cluster. After I moved it to a SQL warehouse, it deleted the entire table. What happened?
The SET spark.sql.sources.partitionOverwriteMode=dynamic that made it work on the cluster is legacy and, in SQL, supported on classic compute only. The warehouse engine does not support it, and the outcome there is undocumented: the write may fail outright, or the ineffective SET may leave static mode in effect. In your run, the latter happened; static mode with no PARTITION clause truncates all table data, as shown in the reproducible example above. Switch the write to INSERT INTO ... REPLACE USING (your partition key): it is compute-independent, atomic, and safe on empty sources — the same statement behaves identically on a cluster, a warehouse, or serverless.
Assumptions: Delta Lake tables on Databricks; SQL examples (documented PySpark/Scala equivalents); runtimes per the version matrix; all compute except where noted (legacy dynamic mode: classic compute only).
Assumptions: Delta Lake tables on Databricks; SQL examples (documented PySpark/Scala equivalents); runtimes per the version matrix; all compute except where noted. Last verified against official Databricks docs: September 30, 2026. Correction history: Sep 30, 2026 — added the missing staging_daily setup with before/after results; replaced undocumented “silently ignored” with “not supported”; qualified wipe claims with the no-PARTITION-clause condition.
RECOMMENDED LEARNING

Replace precisely. Recover deliberately.

Read the selective-overwrite contract, then practice production data-engineering patterns.

Partner links: we may earn a commission if you enroll through these recommendations, at no extra cost to you.