如何在dbt宏中基于SQL设置if-else条件解决数据库重复创建问题
Snowflake dbt宏数据库存在检查失效问题修复
问题背景
在Snowflake环境中编写了自定义dbt宏create_local_database,用于创建本地数据库及对应模式。宏内通过if条件判断同名数据库是否存在,预期数据库已存在时执行else分支,跳过建库脚本仅执行模式创建,但实际运行时else分支未生效,触发“数据库已存在”的编译错误。
原宏代码如下:
{% macro create_local_database(username, reset_environment = false) %} {%- set current_dbt_schemas = ["MART", "MART_ADVANCED"] %} {% set setup_database_name_check %} SELECT DISTINCT DATABASE_NAME FROM SNOWFLAKE.ACCOUNT_USAGE.DATABASES WHERE DATABASE_NAME = 'ANALYTICS_LOCAL_MART_{{username}}' {% endset %} {% set existing_database = run_query(setup_database_name_check).columns[0][0] %} {% if existing_database != 'ANALYTICS_LOCAL_MART_{{username}}' %} {% set setup_database_script %} {%- if reset_environment == false -%} {% do log('Creating Database', True) %} CREATE DATABASE ANALYTICS_LOCAL_MART_{{username}} {%- elif reset_environment == true -%} {{ log(this ~ "Operation Completed : " ~ run_started_at.astimezone(modules.pytz.timezone("America/Chicago")), true) }} CREATE OR REPLACE DATABASE ANALYTICS_LOCAL_MART_{{username}} {% do log('Replaced Database', True) %} {% endif %} {% endset %} {% do run_query(setup_database_script) %} {% for schema in current_dbt_schemas %} {{schema}} {% set setup_schema_script1 %} CREATE SCHEMA IF NOT EXISTS {{schema}} WITH MANAGED ACCESS {{ log(this ~ " Creating Schema (" ~ schema ~ ")" ~ msg, true) }} {% endset %} {% do run_query(setup_schema_script1) %} {% endfor %} {{ log(this ~ "Operation Completed : " ~ run_started_at.astimezone(modules.pytz.timezone("America/Chicago")), true) }} {# the below script is not working#} {% else %} {% for schema in current_dbt_schemas %} {{schema}} {% set setup_schema_script1 %} CREATE SCHEMA IF NOT EXISTS {{schema}} WITH MANAGED ACCESS {{ log(this ~ " Creating Schema (" ~ schema ~ ")" ~ msg, true) }} {% endset %} {% do run_query(setup_schema_script1) %} {% endfor %} {{ log(this ~ "Operation Completed : " ~ run_started_at.astimezone(modules.pytz.timezone("America/Chicago")), true) }} {% endif %} {% endmacro %}
问题根源
- Jinja模板插值错误:if条件判断中
'ANALYTICS_LOCAL_MART_{{username}}'属于嵌套语法错误,Jinja在if语句内不会解析{{ }}标记,导致比较的是字面量字符串而非拼接后的数据库名,条件永远为true,始终执行建库分支。 - 空值未处理:当数据库不存在时,
run_query返回的existing_database为null,直接与字符串比较会引发逻辑判断异常。 - 未定义变量:日志语句中的
msg变量未定义,会触发编译错误。 - 模式创建未指定数据库:创建模式时未明确指定目标数据库,默认使用当前会话数据库,可能导致模式建到错误的库中。
修复后的宏代码
{% macro create_local_database(username, reset_environment = false) %} {%- set target_db = "ANALYTICS_LOCAL_MART_" ~ username %} {%- set current_dbt_schemas = ["MART", "MART_ADVANCED"] %} {% set setup_database_name_check %} SELECT DISTINCT DATABASE_NAME FROM SNOWFLAKE.ACCOUNT_USAGE.DATABASES WHERE DATABASE_NAME = '{{ target_db }}' {% endset %} {% set existing_database = run_query(setup_database_name_check).columns[0][0] %} {% if existing_database is none or existing_database != target_db %} {% set setup_database_script %} {%- if reset_environment == false -%} {% do log('Creating Database: ' ~ target_db, True) %} CREATE DATABASE {{ target_db }} {%- elif reset_environment == true -%} {% do log('Replacing Database: ' ~ target_db, True) %} CREATE OR REPLACE DATABASE {{ target_db }} {% endif %} {% endset %} {% do run_query(setup_database_script) %} {% endif %} {# 无论数据库是否存在,都执行模式创建,避免重复代码 #} {% for schema in current_dbt_schemas %} {% set schema_full_name = target_db ~ "." ~ schema %} {% set setup_schema_script %} CREATE SCHEMA IF NOT EXISTS {{ schema_full_name }} WITH MANAGED ACCESS {% endset %} {% do log('Creating Schema: ' ~ schema_full_name, True) %} {% do run_query(setup_schema_script) %} {% endfor %} {% do log('Operation Completed at: ' ~ run_started_at.astimezone(modules.pytz.timezone("America/Chicago")), true) %} {% endmacro %}
修复说明
- 提前定义
target_db变量统一数据库名,避免重复拼接和语法错误。 - 优化条件判断,先检查
existing_database是否为null,再比较数据库名,确保逻辑正确。 - 移除未定义的
msg变量,简化日志语句。 - 模式创建时使用完整的
数据库.模式命名,确保建在目标数据库下。 - 重构代码,将模式创建逻辑抽离,避免if/else分支重复代码,提高可维护性。
内容的提问来源于stack exchange,提问作者etan
相关产品推荐
相关产品推荐

