如何在DBT中基于字符串列表迭代执行run_query()并为每个结果设置独立变量
如何在DBT中基于字符串列表迭代执行run_query()并为每个结果设置独立变量
嗨,我来帮你搞定这个问题!你想要通过循环自动生成变量、避免重复写run_query和赋值代码的思路非常对,用Jinja的循环完全可以实现,而且代码会非常简洁。下面我分步骤给你讲清楚具体怎么做,还会提供两种实用的实现方式。
核心思路
我们要做的就是:遍历你定义的动物列表,对每个动物执行针对性的SQL查询,把返回的体重值存到对应的变量里。这里要注意Jinja的作用域问题——普通的set在循环里创建的变量是局部的,循环结束后就访问不到了,所以我们需要用命名空间(namespace)或者字典来存储这些动态生成的变量,这样循环外也能正常使用。
方式一:用Jinja Namespace生成独立变量
这种方式会直接生成你想要的ZEBRA_WEIGHT、LION_WEIGHT这类独立变量,和手动赋值的使用体验完全一致:
-- 1. 定义需要获取体重的动物列表,确保和zoo表中animal列的值完全匹配 {% set ANIMALS = ["zebra", "lion", "elephant"] %} -- 2. 创建Jinja命名空间,用来存储动态生成的变量(解决循环作用域问题) {% set ns = namespace() %} -- 3. 循环遍历动物列表,逐个查询体重并赋值 {% for animal in ANIMALS %} {# 构建针对当前动物的SQL查询,用ref('zoo')引用你的zoo模型(dbt会自动处理依赖顺序) #} {% set weight_query %} SELECT weight FROM {{ ref('zoo') }} WHERE animal = '{{ animal }}' {% endset %} {# 执行查询并取出单个结果(每个动物只有一个体重,用scalar()刚好) #} {% set animal_weight = run_query(weight_query).scalar() %} {# 把体重赋值给命名空间中对应的变量,变量名自动转大写并加_WEIGHT后缀 #} {% set ns[animal.upper() ~ "_WEIGHT"] = animal_weight %} {% endfor %} -- 4. 现在就可以像使用普通变量一样调用这些值了! SELECT {{ ns.ZEBRA_WEIGHT }} AS zebra_weight, {{ ns.LION_WEIGHT }} AS lion_weight, {{ ns.ELEPHANT_WEIGHT }} AS elephant_weight FROM some_other_table
关键说明:
namespace()是Jinja的内置对象,用来创建一个可以在循环内外共享的“容器”,避免循环内的变量被局限在局部作用域。run_query(query).scalar():run_query返回的是结果集对象,scalar()方法会直接取出结果集中的第一个值,正好匹配我们“单个体重”的需求。animal.upper() ~ "_WEIGHT":用字符串拼接自动生成变量名,比如zebra转成ZEBRA_WEIGHT,完全符合你的预期。
方式二:用字典存储体重(更灵活)
如果你的动物数量较多,用字典来统一管理所有体重变量会更方便,后续维护也更简单:
-- 1. 定义动物列表 {% set ANIMALS = ["zebra", "lion", "elephant"] %} -- 2. 初始化空字典,用来存动物体重 {% set animal_weights = {} %} -- 3. 循环查询并填充字典 {% for animal in ANIMALS %} {% set weight_query %} SELECT weight FROM {{ ref('zoo') }} WHERE animal = '{{ animal }}' {% endset %} {% set weight = run_query(weight_query).scalar() %} {# 用update方法给字典添加键值对,键是大写动物名+_WEIGHT #} {% do animal_weights.update({animal.upper() ~ "_WEIGHT": weight}) %} {% endfor %} -- 4. 使用字典中的值,两种调用方式都可以 SELECT {{ animal_weights.ZEBRA_WEIGHT }} AS zebra_weight, {{ animal_weights['LION_WEIGHT'] }} AS lion_weight, {{ animal_weights.ELEPHANT_WEIGHT }} AS elephant_weight FROM some_other_table
关键说明:
{% do ... %}是Jinja的语法,用来执行不返回值的操作(比如字典的update),不需要输出内容。- 字典的方式更适合扩展,比如后续要新增动物,只需要在
ANIMALS列表里加名字,不需要修改其他代码。
验证效果
不管用哪种方式,最终得到的变量值和你手动赋值的完全一致:
ns.ZEBRA_WEIGHT(或animal_weights.ZEBRA_WEIGHT)等于400ns.LION_WEIGHT等于200ns.ELEPHANT_WEIGHT等于4000
完全满足你的需求!
备注:内容来源于stack exchange,提问作者Emman
相关产品推荐
相关产品推荐

