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 的调查。
因此,我没有显式声明我需要使用的字段,而是将字段导出到一个数组中,并且我需要在unpivot
的in
子句中使用它们。当我们指定一些字段时,查询工作正常。
【问题讨论】:
如果您修复数据模型,使“变量”列在行中而不是列中,那么您可以轻松解决此问题。 @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() - 如何同步数组并传递额外的数据透视字段?
Snowflake SQL:如何使用 JSON 对象循环遍历数组,以查找符合条件的项目