Skip to content

Commit 11f7cf7

Browse files
Zurbstebenc-db
andauthored
Fix: hard_deletes invalidate incorrectly invalidating active records in snapshots (#1283)
Resolves #1281 ### Description When running a snapshot with `hard_deletes: invalidate`, records that still exist in the source table were being incorrectly marked as invalidated. **Root Cause:** The `when not matched by source` clause (introduced in 1.11.1) matches unchanged records because the staging table only contains *changed* records, not all records. **Solution:** Removed the `when not matched by source` clause. The existing `deletes` CTE already properly handles deletions via `dbt_change_type = 'delete'` and the correct `dbt_scd_id`. We reproduced and verified the fix using the exact example provided in the issue. **Tested on:** SQL Warehouse with Unity Catalog ### Checklist - [x] I have run this code in development and it appears to resolve the stated issue - [x] This PR includes tests, or tests are not required/relevant for this PR - [x] I have updated the `CHANGELOG.md` and added information about my change to the "dbt-databricks next" section. --------- Signed-off-by: Stefan Zurborg <stefan.zurborg@fielmann.com> Co-authored-by: Ben Cassell <98852248+benc-db@users.noreply.github.com>
1 parent 955743a commit 11f7cf7

3 files changed

Lines changed: 19 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
## dbt-databricks 1.11.4 (TBD)
22

33
### Features
4-
- Add `query_id` to `SQLQueryStatus` events to improve query tracing and debugging
4+
- Add `query_id` to `SQLQueryStatus` events to improve query tracing and debugging
5+
6+
### Fixes
7+
- Fix `hard_deletes: invalidate` incorrectly invalidating active records in snapshots (thanks @Zurbste!) ([#1281](https://github.com/databricks/dbt-databricks/issues/1281))
58

69
## dbt-databricks 1.11.3 (Dec 5, 2025)
710

dbt/include/databricks/macros/materializations/snapshot_helpers.sql

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,6 @@
3030
and DBT_INTERNAL_SOURCE.{{ adapter.quote('dbt_change_type') }} = 'insert'
3131
then insert ({{ insert_cols_csv }})
3232
values ({{ insert_cols_csv }})
33-
34-
{%- if invalidate_hard_deletes %}
35-
when not matched by source
36-
and DBT_INTERNAL_DEST.{{ columns.dbt_valid_to }} is null
37-
then update set
38-
{{ columns.dbt_valid_to }} = current_timestamp()
39-
{%- endif %}
4033
;
4134
{% endmacro %}
4235

tests/functional/adapter/simple_snapshot/test_hard_deletes.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,32 @@ def test_hard_delete_invalidate(self, project):
164164
)
165165

166166
# Verify deleted records (3, 4) have dbt_valid_to set (not NULL)
167+
# and non-deleted records (1, 2, 5) have dbt_valid_to = NULL
167168
# Snapshot columns: id, name, city, updated_at, dbt_scd_id,
168169
# dbt_updated_at, dbt_valid_from, dbt_valid_to
169170
# dbt_valid_to is the last column (index -1)
170171
invalidated_count = 0
172+
active_count = 0
171173
for record in final_records:
172-
if record[0] in [3, 4]: # id column
173-
# dbt_valid_to should NOT be NULL
174-
dbt_valid_to = record[-1] # last column
174+
record_id = record[0] # id column
175+
dbt_valid_to = record[-1] # last column
176+
if record_id in [3, 4]:
177+
# Deleted records: dbt_valid_to should NOT be NULL
175178
assert dbt_valid_to is not None, (
176-
f"Record id={record[0]} should have dbt_valid_to set "
179+
f"Record id={record_id} should have dbt_valid_to set "
177180
f"with hard_deletes='invalidate', but got {dbt_valid_to}"
178181
)
179182
invalidated_count += 1
183+
elif record_id in [1, 2, 5]:
184+
# Non-deleted records: dbt_valid_to should be NULL (still active)
185+
assert dbt_valid_to is None, (
186+
f"Record id={record_id} should have NULL dbt_valid_to "
187+
f"(still active), but got {dbt_valid_to}"
188+
)
189+
active_count += 1
180190

181191
assert invalidated_count == 2, f"Expected 2 invalidated records, found {invalidated_count}"
192+
assert active_count == 3, f"Expected 3 active records, found {active_count}"
182193

183194

184195
class TestHardDeleteNewRecord(BaseHardDeleteTest):

0 commit comments

Comments
 (0)