Snowflake 我们如何在字段数组上运行非透视查询而不是显式声明每个字段?

Posted

技术标签:

【中文标题】Snowflake 我们如何在字段数组上运行非透视查询而不是显式声明每个字段?【英文标题】:Snowflake how can we run an unpivot query over an array of fields instead of explicitly declare each field? 【发布时间】:2021-03-01 16:19:00 【问题描述】:

我需要使用数组中指定的字段来取消透视表。我有以下查询:

select
    *
FROM
    TEMP_TABLE_NAME T unpivot (
        val_col for name_col in (
            array_of_fields
        )
    );

问题在于我们的数据是动态的,我们可能会收到包含 10 个字段或 100 个字段的数据,具体取决于我们需要上传到 Snowflake 的调查。

因此,我没有显式声明我需要使用的字段,而是将字段导出到一个数组中,并且我需要在unpivotin 子句中使用它们。当我们指定一些字段时,查询工作正常。

【问题讨论】:

如果您修复数据模型,使“变量”列在行中而不是列中,那么您可以轻松解决此问题。 @GordonLinoff 我们的数据模型基于数据保险库技术和 Microsoft 用于非营利实体的数据模型,这就是我们这样做的原因。 如果这是在存储过程中并且我们使用 javascript 将数组中的字段提取到 IN 子句中,是否有可能? @alim1990 在 cmets 中回答您的问题,是的 - 如果您有动态数量的列要取消透视,您会这样做。 @SimonDarr 如果我们需要将所有内容转换为 varchar 怎么办,因为我们不知道我们有多少字段以及每个字段的类型。 【参考方案1】:

您可以使用 JavaScript UDTF 获得动态反透视:

CREATE OR REPLACE FUNCTION my_unpivot(R OBJECT, A ARRAY)
    RETURNS TABLE (KEY VARCHAR, VALUE VARCHAR)
    LANGUAGE JAVASCRIPT
    AS '

    processRow: function f(row, rowWriter, context)
       for (const element of row.A) 
          rowWriter.writeRow(KEY:element, VALUE:row.R[element]);
       
    
';

SELECT empid, dept, x.key month, x.value sales
FROM (
    select *, object_construct(a.*) obj
    from monthly_sales a
), TABLE(my_unpivot(obj, array_construct('JAN', 'FEB', 'MAR', 'APRIL'))) x
;

本例的样本数据:

create or replace table monthly_sales(empid int, dept text, jan int, feb int, mar int, april int);


insert into monthly_sales values
    (1, 'electronics', 100, 200, 300, 100),
    (2, 'clothes', 100, 300, 150, 200),
    (3, 'cars', 200, 400, 100, 50);

【讨论】:

?关于 JS 函数的想法。虽然在这种情况下它只能用 JSON 重写。我真的希望有一天我们能得到Polymorphic table functions 支持,这是 SQL 标准的一部分 :)【参考方案2】:

我将很快发布一篇关于解决 PIVOT 相同问题的博客,但对于 UNPIVOT 也同样有效。 我更喜欢为这个问题生成视图(但取决于你的需要)。 我有一个包含 VIEW_NAME 和 PIVOT_COLUMN_NAME 的简单表。 我有一个使用 VIEW_NAME 并使用所需 SQL 查询生成 VIEW 的 UDF。

【讨论】:

请不要邀请他人访问您的个人博客。如果需要,您可以在个人资料页面上添加指向该链接的链接。 Pivot 上的博客适用于 Unpivot。您可以在我的个人资料中找到我的博客地址。【参考方案3】:

使用@Felipe's答案中提供的数据:

create or replace table monthly_sales(empid int, dept text,
                                      jan int, feb int, mar int, april int);

insert into monthly_sales(empid, dept, jan, geb, mar, april) values
    (1, 'electronics', 100, 200, 300, 100),
    (2, 'clothes', 100, 300, 150, 200),
    (3, 'cars', 200, 400, 100, 50);

查询可以改写为:

SELECT s.empid, s.dept, f.key AS month, f.value AS sales
FROM ( select a.*, object_construct_keep_null(a.*) AS obj
       from monthly_sales AS a) s
,TABLE(FLATTEN(input => s.obj)) f
WHERE f.KEY IN ('JAN', 'FEB', 'MAR', 'APRIL'); -- here goes list of columns

相关:Is there a melt command in Snowflake?

【讨论】:

以上是关于Snowflake 我们如何在字段数组上运行非透视查询而不是显式声明每个字段?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel,sync() - 如何同步数组并传递额外的数据透视字段?

pandas:如何使用多索引运行数据透视?

Excle数据透视表如何创建非共享缓存的数据透视表

Snowflake SQL:如何使用 JSON 对象循环遍历数组,以查找符合条件的项目

如何授予非管理员用户在 Snowflake 中查看完整的登录历史记录

在我们将其解析为 JSON 之前,Snowflake 如何转义对象数组字符串中的所有特殊字符?