Jinja宏执行异常:批量合并UUID列时表名未正确替换
问题排查与解决:动态生成UNION合并UUID表失败
问题背景
有34张包含UUID列的表,需合并所有UUID到单表。已编写list_tables宏获取test_logs schema下以_semc为后缀的表,但生成的SQL中表名始终是table_name而非实际表名,导致执行失败。
原list_tables宏代码:
{% macro list_tables(schema_name, tables_suffix) %} {% set matching_tables = [] %} {% for table in run_query("select lower(table_name) as table_name from information_schema.tables WHERE lower(table_schema) = '" ~ schema_name ~ "' AND lower(table_name) LIKE '%" ~ tables_suffix ~ "'") %} {% do matching_tables.append(table[0]) %} {% endfor %} {{ matching_tables}} {% endmacro %}
原模型代码:
{{ config(materialized='table', schema='dwh')}} {%set test_logsi = select list_tables('test_logs', '_semc') %} {% for table_name in test_logsi %} SELECT uuid FROM research_db.test_logs.table_name {% if not loop.last %} UNION {% endif %} {% endfor %}
生成的错误SQL:
SELECT uuid FROM research_db.test_logs.table_name UNION SELECT uuid FROM research_db.test_logs.table_name UNION SELECT uuid FROM research_db.test_logs.table_name
错误原因
- 宏返回值错误:原宏最后用
{{ matching_tables }}直接输出列表的字符串形式(如['table1','table2']),而非返回列表对象,导致主模型中test_logsi拿到的是字符串而非可循环的列表。 - 宏调用语法错误:主模型中用
select list_tables(...)是无效语法,Jinja调用宏无需加select。 - 表名未插值:
research_db.test_logs.table_name中的table_name是硬编码字符串,未使用Jinja变量插值语法,导致不会替换为循环中的实际表名。
修复方案
步骤1:修正list_tables宏
将宏的返回方式改为return,确保返回的是列表对象而非字符串,同时优化SQL编写方式提升可读性:
{% macro list_tables(schema_name, tables_suffix) %} {% set matching_tables = [] %} {% set query %} SELECT lower(table_name) as table_name FROM information_schema.tables WHERE lower(table_schema) = '{{ schema_name | lower }}' AND lower(table_name) LIKE '%{{ tables_suffix | lower }}' {% endset %} {% for table in run_query(query).columns[0].values() %} {% do matching_tables.append(table) %} {% endfor %} {% do return(matching_tables) %} {% endmacro %}
步骤2:修正主模型代码
- 移除宏调用前的
select关键字 - 使用Jinja插值语法
{{ table_name }}替换硬编码的table_name - 可选:用
UNION ALL替代UNION(无需去重时性能更优,需去重则保留UNION)
修正后的模型代码:
{{ config(materialized='table', schema='dwh')}} {% set test_logsi = list_tables('test_logs', '_semc') %} {% for table_name in test_logsi %} SELECT uuid FROM research_db.test_logs.{{ table_name }} {% if not loop.last %} UNION ALL {% endif %} {% endfor %}
验证效果
修正后生成的SQL会自动替换为实际表名,示例如下:
SELECT uuid FROM research_db.test_logs.user_semc UNION ALL SELECT uuid FROM research_db.test_logs.order_semc UNION ALL SELECT uuid FROM research_db.test_logs.product_semc ...
内容的提问来源于stack exchange,提问作者Sefi
相关产品推荐
相关产品推荐

