带有 dbt 宏的动态列的 Snowflake "Pivot"

Snowflake "Pivot" for dynamic columns with dbt macro

起始上下文:

  1. 有一个dbt_utils“枢轴”功能。这个问题与那个函数有关。

  2. 存在some discussion about the limitations of Snowflake's built-in PIVOT,即无法为此函数使用动态列and/or值。

example_model.sql

with pivot as (
    select * 
    from {{ ref('my_base_model') }}
        pivot( sum(VALUE) for KEY in ( 
        {{ dbt_utils.get_column_values(table=ref('my_base_model'), column='KEY') }} 
        ) )
)

select * from pivot

dbt 轻松解决了这个问题,除了一个小问题。当上面的代码被编译时(下面的代码块),它生成值作为 python 列表 [...] 当雪花期待更像一个元组 (...)

with pivot as (
    select * 
    from DB.SCHEMA.my_base_model
        pivot( sum(VALUE) for KEY in ( ['value_1', 'value_2', 'value_3', 'value_4', 'value_5', 'value_6', 'value_7'] ) )
)

select * from pivot

我正在考虑使用 as_native 之类的方法将结果列表转换为元组,但到目前为止没有成功。

dbt run 内的错误:

001003 (42000): SQL compilation error:
  syntax error line 5 at position 39 unexpected '['.
  syntax error line 5 at position 961 unexpected ']'.
  compiled SQL at target\run\dbtproject\models\staging\my_application
\my_base_model.sql

也许不是最好的答案,但一个可行的答案是:

pivot_model.sql

{% set pivot_cols = dbt_utils.get_column_values(table=ref('my_base_model'), column='KEY') %}

with pivot as (
    select * 
    from {{ ref('my_base_model') }}
        pivot( sum(VALUE) for KEY in (
            {% for pivot_col in pivot_cols %}
                '{{pivot_col}}'{% if not loop.last %}, {% endif%}
            {% endfor %}
         ))
)

select * from pivot

** 更新 2 **: 由于 Jinja 不支持 tuple 作为过滤器,因此我们可以使用 join 代替:

with pivot as (
    select * 
    from {{ ref('my_base_model') }}
        pivot( sum(VALUE) for KEY in ( 
        {{ dbt_utils.get_column_values(table=ref('my_base_model'), column='KEY') | join(",") }} 
        )
)

select * from pivot

** 更新 1 **: 如果你想用 dbt 来做,让我们试试这个:

  1. dbt_utils.get_column_values的结果转换为tuple
with pivot as (
    select * 
    from {{ ref('my_base_model') }}
        pivot( sum(VALUE) for KEY in ( 
        {{ dbt_utils.get_column_values(table=ref('my_base_model'), column='KEY') | tuple }} 
        ) )
)

select * from pivot
  1. 您始终可以尝试创建自定义 dbt 宏,它是本地项目中 dbt_utils.get_column_values 的副本并使用它:

来源get_column_values

自定义:

...
{%- set values = value_list['data'] | map(attribute=0) | tuple %}
...

** 来源 ** 请仔细看pivot doc.

SELECT ...
FROM ...
   PIVOT ( <aggregate_function> ( <pivot_column> )
            FOR <value_column> IN ( <pivot_value_1> [ , <pivot_value_2> ... ] ) )

[ ... ]

它没有 [ ],这在您的查询中是不正确的

所以修复应该是:

with pivot as (
    select * 
    from DB.SCHEMA.my_base_model
        pivot( sum(VALUE) for KEY in ( 'value_1', 'value_2', 'value_3', 'value_4', 'value_5', 'value_6', 'value_7' ) )
)

select * from pivot