如何将变量解析为 dbt 中的源引用? 问题

问题描述

我正在构建一个模型,根据查询结果动态引用表名和模式名。

    {%- set query %}
        select * from master_data.event_Metadata where game='{{game_name}}'
    {% endset -%}
    {%- set results = run_query(query) -%}
    {%- if execute %}
        {%- set record = results.rows[0] -%}
    {% else %}
        {%- set record = [] -%}
    {% endif -%}

其中两个值在 record.SCHEMA_NAMErecord.TABLE_NAME 中。我可以使用类似的东西

select
    *
from
    {{record.SCHEMA_NAME}}.{{record.TABLE_NAME}}

但我宁愿使用 source() 函数,以便我的文档和 DAG 保持干净。如何将 record.SCHEMA_NAMErecord.TABLE_NAME 解析为字符串参数。我需要有类似的东西

select
    *
from
    {{ source(record.SCHEMA_NAME,record.TABLE_NAME) }}

当我尝试运行上述程序时,出现以下错误

Server error: Compilation Error in rpc request (from remote system)
The source name (first) argument to source() must be a string,got <class 'jinja2.runtime.Undefined'>

解决方法

我认为您需要先将这两个对象转换为它们的字符串表示形式,然后再将它们传递给 source 宏。

试试这个

select
    *
from
    {{ source(record.SCHEMA_NAME|string,record.TABLE_NAME||string) }}
,

您可能已经找到了解决方法或解决方案,但以防万一其他人遇到同样的情况...

要将值转换为字符串,您可以使用 |string。例如:

record.SCHEMA_NAME|string
record.TABLE_NAME|string

所以你的查询看起来像这样:

select * from {{ source(record.SCHEMA_NAME|string|lower,record.TABLE_NAME|string|lower) }}

请注意,根据您查询的输出以及您定义源文件的方式,您可能必须lowerupper 您的值才能与您的源匹配。

问题

您的 record 变量是执行 (run_query(query)) 的结果。当你做 dbt compile/run 时,dbt 会做一系列的操作,比如读取你项目的所有文件,生成一个“manifest.json”文件,并且会使用 ref/source 来生成DAG 所以在这一点上,没有执行 SQL,换句话说,execute == False

在您的示例中,即使您执行 record.SCHEMA_NAME|string,您也无法检索该变量的值,因为没有执行任何操作,并且由于您执行了 if not execute then record = [] ,您将收到该消息 {{1 }},因为此时 ... depends on a source named '.' which was not found 是空的。

一种解决方法是将模型的查询包装在 record 块中,如下所示:

if execute

通过这种方法,您将能够动态设置模型的来源。

但不幸的是,这不会像您预期的那样工作,因为它不会为该模型生成 DAG。使用 {% if execute %} select * from {{ source(record.TABLE_SCHEMA|string|lower,record.TABLE_NAME|string|lower) }} {% endif %} 块来包装模型的查询将阻止 dbt 为模型生成 DAG。

最后,这将与您第一次尝试在没有 if execute 函数的情况下声明 schematable 相同。

有关更多详细信息,您可以查看有关 source 的 dbt 文档: https://docs.getdbt.com/reference/dbt-jinja-functions/execute