dbt中pre_hook传递宏变量异常:get_date返回值未正确传入insert_table
问题原因与解决方案
原因分析
dbt存在两个核心执行阶段,这是问题的关键:
- 项目解析阶段:dbt读取所有模型配置、渲染宏的静态内容,此时
execute变量为False——因为还未开始执行任何SQL操作。 - 模型执行阶段:dbt开始运行模型对应的SQL逻辑,此时
execute变量为True,可以执行数据库查询。
你的代码存在执行时机不匹配的问题:
- 模型里的
{% set my_date = get_date() %}是在模型执行阶段运行的,此时execute=True,能正确获取数据库中的最新日期2024-05-05。 - 但你用字符串拼接的方式把
insert_table宏写在pre_hook中,这部分配置会在项目解析阶段被渲染。此时调用get_date()时execute=False,只能返回默认值2024-04-01,这个值被硬编码进了pre_hook的SQL中,和模型执行阶段的my_date完全无关。
解决方法
以下是两种可靠的修正方式:
方法一:让insert_table宏内部动态获取日期
修改insert_table宏,让它自己调用get_date()获取日期,确保在执行阶段才查询数据库:
{% macro insert_table(pre_hook=false) %} {% if execute %} {% set report_date = get_date() %} insert into public.my_table values ('{{ report_date }}', current_timestamp, 0) {% endif %} {% endmacro %}
模型配置简化为直接调用宏:
{{ config( pre_hook=[ "{{ insert_table(pre_hook=True) }}" ] ) }}
方法二:将pre_hook改为执行阶段渲染的Jinja表达式
去掉pre_hook的字符串包裹,直接传递Jinja表达式,让它在模型执行阶段才渲染:
{{ config( pre_hook=insert_table(report_date=get_date(), pre_hook=True) ) }}
这种写法下,insert_table宏会在execute=True的阶段被调用,get_date()能正确返回数据库中的最新日期。
内容的提问来源于stack exchange,提问作者MADAO_MAN
相关产品推荐
相关产品推荐

