dbt+Databricks快照timestamp策略报错:时间戳未加引号引发语法错误
解决dbt Cloud + Databricks的timestamp策略快照语法错误问题
问题重现
使用dbt Cloud IDE搭配Databricks,采用timestamp策略创建快照,指定updated_at为created_at列,快照代码如下:
{% snapshot products_snapshot %} {{ config( target_schema='bronze', strategy='timestamp', unique_key='id', updated_at='created_at' ) }} select * from {{ source('landing', 'products') }} {% endsnapshot %}
执行dbt snapshot时触发[PARSE_SYNTAX_ERROR],原因是生成的SQL中时间戳字面量未被引号包裹,导致Databricks无法识别格式。
解决方案
1. 确保时间戳列类型正确
如果源表的created_at是字符串类型,Databricks无法直接识别为时间格式进行比较,需显式转换为timestamp类型:
{% snapshot products_snapshot %} {{ config( target_schema='bronze', strategy='timestamp', unique_key='id', updated_at='created_at' ) }} select id, name, -- 替换为你的实际业务字段 price, cast(created_at as timestamp) as created_at -- 显式转换为timestamp类型 from {{ source('landing', 'products') }} {% endsnapshot %}
若字符串格式非Databricks默认格式(如yyyy-MM-dd HH:mm:ss),需指定格式转换:
cast(created_at as timestamp format 'yyyy/MM/dd HH:mm:ss') as created_at
2. 升级dbt-databricks适配器
旧版本的dbt-databricks适配器可能存在timestamp策略下生成SQL的bug,导致时间戳字面量未正确添加引号。在dbt Cloud的项目设置中,将dbt-databricks依赖升级至最新稳定版,重新执行快照命令。
3. 自定义快照宏修复SQL生成逻辑
如果上述方法无效,可自定义宏覆盖默认的timestamp策略SQL生成逻辑,确保时间戳值被正确包裹:
在项目的macros/snapshots目录下新建custom_timestamp_snapshot.sql文件,内容如下:
{% macro get_timestamp_snapshot_sql(target_relation, source_relation, snapshot_args) %} {% set unique_key = snapshot_args['unique_key'] %} {% set updated_at = snapshot_args['updated_at'] %} {% set snapshot_id = snapshot_args['snapshot_id'] %} {% set select_new_rows = %} select s.*, current_timestamp() as dbt_valid_from, cast(null as timestamp) as dbt_valid_to, '{{ snapshot_id }}' as dbt_snapshot_id from {{ source_relation }} s left join {{ target_relation }} t on s.{{ unique_key }} = t.{{ unique_key }} where t.{{ unique_key }} is null or s.{{ updated_at }} > coalesce(t.{{ updated_at }}, '1970-01-01 00:00:00'::timestamp) {% endset %} {% set update_old_rows = %} update {{ target_relation }} t set dbt_valid_to = current_timestamp(), dbt_snapshot_id = '{{ snapshot_id }}' from {{ source_relation }} s where t.{{ unique_key }} = s.{{ unique_key }} and s.{{ updated_at }} > t.{{ updated_at }} and t.dbt_valid_to is null {% endset %} {% do return([select_new_rows, update_old_rows]) %} {% endmacro %}
保存后重新执行dbt snapshot,宏会确保时间戳字面量被引号包裹并正确转换类型。
内容的提问来源于stack exchange,提问作者Datapher
相关产品推荐
相关产品推荐

