You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

dbt快照调用列名获取宏报错:'None' has no attribute 'table'

解决dbt快照中使用动态列名宏出现的'None' has no attribute 'table'错误

问题根源

dbt快照的check_cols参数在编译阶段就会被评估,而你编写的宏如果依赖运行时上下文(比如model.table对象)或动态查询INFORMATION_SCHEMA,编译阶段这些对象/查询结果还未初始化,就会抛出None属性错误。硬编码列名能正常运行,是因为静态值在编译阶段可直接解析,无需依赖运行时资源。

解决方案

针对dbt-core1.5、dbt-bigquery1.5版本,提供三种可行修复方案:

方案1:直接指定表信息,避免依赖上下文对象

修改宏,通过传入明确的schema和表名查询INFORMATION_SCHEMA,同时添加编译阶段的占位值避免报错:

{% macro get_column_names_excl_meta_cols(schema_name, table_name, exclude_cols=['dbt_updated_at', 'dbt_valid_from', 'dbt_valid_to']) %}
  {% set query %}
    SELECT column_name
    FROM {{ schema_name }}.INFORMATION_SCHEMA.COLUMNS
    WHERE table_name = '{{ table_name }}'
      AND column_name NOT IN ({{ exclude_cols | map('quote') | join(', ') }})
    ORDER BY ordinal_position
  {% endset %}
  {% set results = run_query(query) %}
  {% if execute %}
    {{ results.columns[0].values() | join(', ') }}
  {% else %}
    -- 编译阶段返回占位值,跳过语法检查
    'placeholder_col'
  {% endif %}
{% endmacro %}

快照中调用时传入明确的schema和表名:

{% snapshot store_hist %}
{{
    config(
      target_schema='snapshots',
      strategy='check',
      check_cols=[{{ get_column_names_excl_meta_cols('your_source_schema', 'store') }}],
      unique_key='store_id'
    )
}}

select * from {{ source('my_source', 'store') }}
{% endsnapshot %}

方案2:使用dbt内置适配器方法获取列信息(推荐)

用dbt内置的adapter.get_columns_in_relation替代手动查询INFORMATION_SCHEMA,该方法在编译阶段即可获取已存在表的列信息,更适配dbt上下文:

{% macro get_column_names_excl_meta_cols(relation, exclude_cols=['dbt_updated_at', 'dbt_valid_from', 'dbt_valid_to']) %}
  {% set cols = adapter.get_columns_in_relation(relation) %}
  {% set filtered_cols = cols | rejectattr('name', 'in', exclude_cols) | map(attribute='name') %}
  {% if execute %}
    {{ filtered_cols | join(', ') }}
  {% else %}
    ''
  {% endif %}
{% endmacro %}

快照中先获取源关系再传入宏:

{% snapshot store_hist %}
{% set source_relation = source('my_source', 'store') %}
{{
    config(
      target_schema='snapshots',
      strategy='check',
      check_cols=[{{ get_column_names_excl_meta_cols(source_relation) }}],
      unique_key='store_id'
    )
}}

select * from {{ source_relation }}
{% endsnapshot %}

方案3:预生成列名清单(适配快照编译逻辑)

如果上述方法仍有问题,可单独创建宏预生成列名列表,直接返回给check_cols:

  1. 创建预生成列名的宏:
{% macro get_store_check_cols() %}
  {% set cols = adapter.get_columns_in_relation(source('my_source', 'store')) %}
  {% set filtered_cols = cols | rejectattr('name', 'in', ['dbt_updated_at', 'dbt_valid_from', 'dbt_valid_to']) | map(attribute='name') %}
  {% if execute %}
    {{ filtered_cols | list }}
  {% else %}
    []
  {% endif %}
{% endmacro %}
  1. 快照中直接引用宏结果:
{% snapshot store_hist %}
{{
    config(
      target_schema='snapshots',
      strategy='check',
      check_cols={{ get_store_check_cols() }},
      unique_key='store_id'
    )
}}

select * from {{ source('my_source', 'store') }}
{% endsnapshot %}

注意事项

  • 确保源表/上游模型在运行快照前已存在(可先执行dbt run再跑dbt snapshot),否则适配器方法无法获取列信息。
  • dbt 1.5中check_cols接受列名列表,宏需返回逗号分隔的字符串(方案1、2)或直接返回列表(方案3)。
  • 所有动态逻辑必须添加execute条件判断,并提供编译阶段的 fallback 值,避免语法解析错误。

内容的提问来源于stack exchange,提问作者VKarthik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:02:48