dbt-labs / dbt-labs/dbt-adapters

[Bug] snapshot single unique_key string treated as an iterable

Open
#1,188 4 comments 0 reactions 0 assignees View on GitHub
feature:snapshots pkg:dbt-snowflake type:bug
Dominant language
Python
Stars
233
Forks
362
Avg merge
3d 22h
Merged PRs (30d)
9

Description

### Is this a new bug?

- [x] I believe this is a new bug
- [x] I have searched the existing issues, and I could not find an existing issue for this bug

### Which packages are affected?

- [ ] dbt-adapters
- [ ] dbt-tests-adapter
- [ ] dbt-athena
- [ ] dbt-athena-community
- [ ] dbt-bigquery
- [ ] dbt-postgres
- [ ] dbt-redshift
- [x] dbt-snowflake
- [ ] dbt-spark

### Current Behavior

I have a snapshot with the following config:
```
- name: snap_mart_advances
config:
strategy: check
unique_key: advance_record_id
check_cols: ['column_a', 'column_b']
```

When I added a `column_c` to `check_cols` and ran `dbt snapshot --select snap_mart_advances`, I got the following dbt error:
```
001003 (42000): SQL compilation error:
syntax error line 43 at position 12 unexpected '_'.
syntax error line 45 at position 17 unexpected 'dbt_unique_key_9'.
syntax error line 47 at position 17 unexpected 'dbt_unique_key_10'.
syntax error line 49 at position 17 unexpected 'dbt_unique_key_11'.
syntax error line 51 at position 17 unexpected 'dbt_unique_key_12'.
syntax error line 53 at position 17 unexpected 'dbt_unique_key_13'.
syntax error line 55 at position 17 unexpected 'dbt_unique_key_14'.
syntax error line 57 at position 12 unexpected '_'.
syntax error line 57 at position 17 unexpected 'dbt_unique_key_15'.
syntax error line 59 at position 17 unexpected 'dbt_unique_key_16'.
syntax error line 61 at position 17 unexpected 'dbt_unique_key_17'.
syntax error line 65 at position 8 unexpected 'from'.
syntax error line 71 at position 5 unexpected ','.
```

I looked at the query issued to Snowflake, and saw the following:
```
create or replace temporary table "DEVELOPMENT"."SNAPSHOTS"."SNAP_MART_ADVANCES__dbt_tmp"
as
(

with snapshot_query as (

select advance_record_id,
column_a,
column_b,
column_c
from DEVELOPMENT.DBT_shansen.mart_advances

),

snapshotted_data as (

select *,


a as dbt_unique_key_1 ,

d as dbt_unique_key_2 ,

v as dbt_unique_key_3 ,

a as dbt_unique_key_4 ,

n as dbt_unique_key_5 ,

c as dbt_unique_key_6 ,

e as dbt_unique_key_7 ,

_ as dbt_unique_key_8 ,

r as dbt_unique_key_9 ,

e as dbt_unique_key_10 ,

c as dbt_unique_key_11 ,

o as dbt_unique_key_12 ,

r as dbt_unique_key_13 ,

d as dbt_unique_key_14 ,

_ as dbt_unique_key_15 ,

i as dbt_unique_key_16 ,

d as dbt_unique_key_17

from "DEVELOPMENT"."SNAPSHOTS"."SNAP_MART_ADVANCES"
where

dbt_valid_to is null

),

insertions_source_data as (

select *,


a as dbt_unique_key_1 ,

d as dbt_unique_key_2 ,

v as dbt_unique_key_3 ,

a as dbt_unique_key_4 ,

n as dbt_unique_key_5 ,

c as dbt_unique_key_6 ,

e as dbt_unique_key_7 ,

_ as dbt_unique_key_8 ,

r as dbt_unique_key_9 ,

e as dbt_unique_key_10 ,

c as dbt_unique_key_11 ,

o as dbt_unique_key_12 ,

r as dbt_unique_key_13 ,

d as dbt_unique_key_14 ,

_ as dbt_unique_key_15 ,

i as dbt_unique_key_16 ,

d as dbt_unique_key_17


,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_updated_at,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_from,


coalesce(nullif(to_timestamp_ntz(convert_timezone('UTC', current_timestamp())), to_timestamp_ntz(convert_timezone('UTC', current_timestamp()))), null)
as dbt_valid_to
,
md5(coalesce(cast(a as varchar ), '')
|| '|' || coalesce(cast(d as varchar ), '')
|| '|' || coalesce(cast(v as varchar ), '')
|| '|' || coalesce(cast(a as varchar ), '')
|| '|' || coalesce(cast(n as varchar ), '')
|| '|' || coalesce(cast(c as varchar ), '')
|| '|' || coalesce(cast(e as varchar ), '')
|| '|' || coalesce(cast(_ as varchar ), '')
|| '|' || coalesce(cast(r as varchar ), '')
|| '|' || coalesce(cast(e as varchar ), '')
|| '|' || coalesce(cast(c as varchar ), '')
|| '|' || coalesce(cast(o as varchar ), '')
|| '|' || coalesce(cast(r as varchar ), '')
|| '|' || coalesce(cast(d as varchar ), '')
|| '|' || coalesce(cast(_ as varchar ), '')
|| '|' || coalesce(cast(i as varchar ), '')
|| '|' || coalesce(cast(d as varchar ), '')
|| '|' || coalesce(cast(to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as varchar ), '')
) as dbt_scd_id

from snapshot_query
),

updates_source_data as (

select *,


a as dbt_unique_key_1 ,

d as dbt_unique_key_2 ,

v as dbt_unique_key_3 ,

a as dbt_unique_key_4 ,

n as dbt_unique_key_5 ,

c as dbt_unique_key_6 ,

e as dbt_unique_key_7 ,

_ as dbt_unique_key_8 ,

r as dbt_unique_key_9 ,

e as dbt_unique_key_10 ,

c as dbt_unique_key_11 ,

o as dbt_unique_key_12 ,

r as dbt_unique_key_13 ,

d as dbt_unique_key_14 ,

_ as dbt_unique_key_15 ,

i as dbt_unique_key_16 ,

d as dbt_unique_key_17


,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_updated_at,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_from,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_to

from snapshot_query
),

insertions as (

select
'insert' as dbt_change_type,
source_data.*

from insertions_source_data as source_data
left outer join snapshotted_data
on




(snapshotted_data.dbt_unique_key_1 = source_data.dbt_unique_key_1)
and



(snapshotted_data.dbt_unique_key_2 = source_data.dbt_unique_key_2)
and



(snapshotted_data.dbt_unique_key_3 = source_data.dbt_unique_key_3)
and



(snapshotted_data.dbt_unique_key_4 = source_data.dbt_unique_key_4)
and



(snapshotted_data.dbt_unique_key_5 = source_data.dbt_unique_key_5)
and



(snapshotted_data.dbt_unique_key_6 = source_data.dbt_unique_key_6)
and



(snapshotted_data.dbt_unique_key_7 = source_data.dbt_unique_key_7)
and



(snapshotted_data.dbt_unique_key_8 = source_data.dbt_unique_key_8)
and



(snapshotted_data.dbt_unique_key_9 = source_data.dbt_unique_key_9)
and



(snapshotted_data.dbt_unique_key_10 = source_data.dbt_unique_key_10)
and



(snapshotted_data.dbt_unique_key_11 = source_data.dbt_unique_key_11)
and



(snapshotted_data.dbt_unique_key_12 = source_data.dbt_unique_key_12)
and



(snapshotted_data.dbt_unique_key_13 = source_data.dbt_unique_key_13)
and



(snapshotted_data.dbt_unique_key_14 = source_data.dbt_unique_key_14)
and



(snapshotted_data.dbt_unique_key_15 = source_data.dbt_unique_key_15)
and



(snapshotted_data.dbt_unique_key_16 = source_data.dbt_unique_key_16)
and



(snapshotted_data.dbt_unique_key_17 = source_data.dbt_unique_key_17)


where

snapshotted_data.dbt_unique_key_1 is null

or (

snapshotted_data.dbt_unique_key_1 is not null

and ()

),

updates as (

select
'update' as dbt_change_type,
source_data.*,
snapshotted_data.dbt_scd_id

from updates_source_data as source_data
join snapshotted_data
on




(snapshotted_data.dbt_unique_key_1 = source_data.dbt_unique_key_1)
and



(snapshotted_data.dbt_unique_key_2 = source_data.dbt_unique_key_2)
and



(snapshotted_data.dbt_unique_key_3 = source_data.dbt_unique_key_3)
and



(snapshotted_data.dbt_unique_key_4 = source_data.dbt_unique_key_4)
and



(snapshotted_data.dbt_unique_key_5 = source_data.dbt_unique_key_5)
and



(snapshotted_data.dbt_unique_key_6 = source_data.dbt_unique_key_6)
and



(snapshotted_data.dbt_unique_key_7 = source_data.dbt_unique_key_7)
and



(snapshotted_data.dbt_unique_key_8 = source_data.dbt_unique_key_8)
and



(snapshotted_data.dbt_unique_key_9 = source_data.dbt_unique_key_9)
and



(snapshotted_data.dbt_unique_key_10 = source_data.dbt_unique_key_10)
and



(snapshotted_data.dbt_unique_key_11 = source_data.dbt_unique_key_11)
and



(snapshotted_data.dbt_unique_key_12 = source_data.dbt_unique_key_12)
and



(snapshotted_data.dbt_unique_key_13 = source_data.dbt_unique_key_13)
and



(snapshotted_data.dbt_unique_key_14 = source_data.dbt_unique_key_14)
and



(snapshotted_data.dbt_unique_key_15 = source_data.dbt_unique_key_15)
and



(snapshotted_data.dbt_unique_key_16 = source_data.dbt_unique_key_16)
and



(snapshotted_data.dbt_unique_key_17 = source_data.dbt_unique_key_17)


where (
()
)

select * from insertions
union all
select * from updates

);
```

I suspect that the functionality to use multiple unique_keys in [this PR ](https://github.com/dbt-labs/dbt-adapters/pull/326) is somehow enabling dbt to treat the `advance_record_id` string as an iterable, and iterate through each character as elements of a list.

The error only appeared sometimes -- if I removed and re-added the column_c for example, the snapshot job ran fine.

### Expected Behavior

Here is how the snowflake query looks on successful snapshot runs:
```
create or replace temporary table "DEVELOPMENT"."SNAPSHOTS"."SNAP_MART_ADVANCES__dbt_tmp"
as
(

with snapshot_query as (

select advance_record_id,

from DEVELOPMENT.DBT_shansen.mart_advances

),

snapshotted_data as (

select *,

advance_record_id as dbt_unique_key

from "DEVELOPMENT"."SNAPSHOTS"."SNAP_MART_ADVANCES"
where

dbt_valid_to is null

),

insertions_source_data as (

select *,

advance_record_id as dbt_unique_key

,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_updated_at,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_from,


coalesce(nullif(to_timestamp_ntz(convert_timezone('UTC', current_timestamp())), to_timestamp_ntz(convert_timezone('UTC', current_timestamp()))), null)
as dbt_valid_to
,
md5(coalesce(cast(advance_record_id as varchar ), '')
|| '|' || coalesce(cast(to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as varchar ), '')
) as dbt_scd_id

from snapshot_query
),

updates_source_data as (

select *,

advance_record_id as dbt_unique_key

,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_updated_at,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_from,
to_timestamp_ntz(convert_timezone('UTC', current_timestamp())) as dbt_valid_to

from snapshot_query
),

insertions as (

select
'insert' as dbt_change_type,
source_data.*

from insertions_source_data as source_data
left outer join snapshotted_data
on

snapshotted_data.dbt_unique_key = source_data.dbt_unique_key

where

snapshotted_data.dbt_unique_key is null

or (

snapshotted_data.dbt_unique_key is not null

and ()
)

),

updates as (

select
'update' as dbt_change_type,
source_data.*,
snapshotted_data.dbt_scd_id

from updates_source_data as source_data
join snapshotted_data
on

snapshotted_data.dbt_unique_key = source_data.dbt_unique_key

where ()
)

select * from insertions
union all
select * from updates

);
```

### Steps To Reproduce

1. To an existing snapshot with `check` strategy and one `unique_key`, add a column to `check_cols`
2. Run `dbt snapshot --select `
3. Check if this error happens

### Relevant log output

```shell

```

### Environment

```markdown
- OS: Sequoia 15.5
- Python: 3.12.10
- dbt-core: 1.9.3
- dbt-adapters: ?
- dbt-snowflake: 1.9.0
```

### Additional Context

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.