【问题标题】:Snowflake "Pivot" for dynamic columns with dbt macro带有 dbt 宏的动态列的雪花“枢轴”
【发布时间】:2021-12-26 23:23:00
【问题描述】:

起始上下文:

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

  2. somediscussion关于雪花内置PIVOT的限制,即无法使用动态列和/或该函数的值。

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

【问题讨论】:

    标签: jinja2 snowflake-cloud-data-platform dbt


    【解决方案1】:

    ** 更新 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
    

    【讨论】:

    • 嗨,Dat,如果这是一个仅使用 SnowSQL 的静态类型脚本 - 这个答案将是完美的。但是,我试图在 dbt 中复制此功能,这意味着您的答案不适用于此要求。
    • @sgoley 哎呀对不起,我的错误是没有仔细阅读问题。所以你的答案将是完美的兄弟!另一种方法我们可以尝试将dbt_utils.get_column_values 的结果转换为tuple 类型而不是list 类型
    • @sgoley 更新了我的答案。感谢您的评论
    • Dat,请注意,目前从 dbt 的 0.21 版和 dbt-utils 的 0.7.0 版开始,` |元组`修饰符返回以下错误:no filter named 'tuple'
    • @sgoley:是的,你是对的! ({{ dbt.utils... | join(",")}})呢?
    【解决方案2】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多