为何DBT增量模型中宏先于pre_hook语句执行?
问题原因
dbt的执行分为编译阶段和运行阶段:
- 编译阶段:模型中的宏(比如
append_placekeys)会被直接展开为SQL语句,成为模型最终SQL的一部分。 - 运行阶段:先执行
pre_hook配置中的SQL,再执行模型的主SQL。
你当前的写法是把append_placekeys宏放在模型主SQL里,这会导致该宏对应的CALL语句在编译阶段就被写入主SQL。而pre_hook的建表语句要等到运行阶段、主SQL执行前才会执行,所以日志里显示宏先执行,临时表后创建。
解决方案
把append_placekeys宏的调用移到pre_hook列表中,放在创建临时表的语句之后,确保执行顺序为:建临时表 → 调用宏处理数据 → 模型主SQL读取处理后的临时表。
修改后的模型代码如下:
{{ config( materialized='incremental', unique_key='DX_ID', pre_hook=[ """ CREATE OR REPLACE TEMP TABLE DXH_STORE_PLCK_IN AS SELECT DISTINCT s.dx_id AS msa_id, s.nm AS store_name, s.city AS city, s.state AS state, s.address AS street_addr, s.zip5 AS zipcode, s.country AS COUNTRY_CODE, s.latitude AS LATITUDE, s.longitude AS LONGITUDE, COALESCE(p.last_updt_dt, TO_DATE('2023-01-01')) AS last_updt_dt FROM {{ ref('dx_store_attr') }} s {%- if is_incremental() %} FULL JOIN {{ this }} p USING (dx_id) WHERE ( p.placekey IS NULL OR DATEDIFF(day, p.last_updt_dt::DATE, CURRENT_TIMESTAMP()::DATE) > 90 ) ORDER BY last_updt_dt ASC, s.dx_id ASC LIMIT 3000 {%- else %} LIMIT 50000 {%- endif -%} ; """, # 将宏调用加入pre_hook,放在建表语句之后 "{{ append_placekeys(tbl_in='DXH_STORE_PLCK_IN', tbl_out='DXH_STORE_PLCK_TEMP') }}" ], tags=["dx", "refresh:daily"] ) }} SELECT t.msa_id AS dx_id, t.placekey AS placekey, t.error AS error, CURRENT_TIMESTAMP() AS last_updt_dt FROM {{ database }}.{{ schema }}.DXH_STORE_PLCK_TEMP AS t
补充说明
pre_hook列表中的语句会按照从上到下的顺序依次执行,确保依赖关系正确。- 如果
append_placekeys宏内部有动态生成逻辑,这种写法依然能正常工作,因为pre_hook中的jinja表达式会在编译阶段展开,运行阶段按顺序执行。
内容的提问来源于stack exchange,提问作者Raul E. Menendez
相关产品推荐
相关产品推荐

