dbt-labs / dbt-labs/dbt-adapters
[Bug] snapshot single unique_key string treated as an iterable
- 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
Assessment
This issue has not been assessed yet.