雪花 SQL udf 的输入列表

Posted

技术标签:

【中文标题】雪花 SQL udf 的输入列表【英文标题】:Input list to Snowflake SQL udf 【发布时间】:2021-09-28 14:45:30 【问题描述】:

我创建了一个 Snowflake SQL udf,我使用以下代码调用:

select *
from table(drill_top_down('12345','XXX)) order by depth,path;

如果我需要对多个项目运行查询,是否可以输入一个列表或类似于 udf 的列表,然后循环遍历我的输入列表?

或者我能否以更智能的方式调用我的函数,以便从多个输入中获取结果?

【问题讨论】:

【参考方案1】:

您可以提供一个 Snowflake Array、Object 或 Variant,其中嵌套了您的参数集,并将其用作表函数的输入。

调整您的示例,使用数组构造提供两组参数,输入看起来像:

select *
from table(drill_top_down( 
            array_construct(
                  array_construct('12345','XXX'),
                  array_construct('67890','YYY')
                       )::array;

或者我更喜欢使用 parse_json,因为我觉得它更容易阅读

select *
from table(drill_top_down(parse_json('
                             [ ["12345","XXX"],
                               ["67890","YYY"]  ]')::array;

您将需要调整您的表函数以使用公共表表达式 (CTE) 解压缩参数集以将输入参数表格化,然后使用横向展平将它们取消嵌套。

这是一个简单的例子:

CREATE OR REPLACE FUNCTION array_concat ( arr array)
  RETURNS TABLE ( concatenated_string varchar )
  AS 
  $$
  With a as (Select arr)
  Select listagg(value)
  From a, table(flatten(input => arr))
  $$
  ;

这是一个稍微复杂的示例,它对每个参数集执行一个操作,使用 row_number() 对它们进行分组。

CREATE OR REPLACE FUNCTION array_calcs ( arg_list array)
  RETURNS TABLE 
     ( arg_id integer,
       array_sz integer,
       array_sum integer,
       array_mean decimal(12,2) )
  AS 
  $$
  With 
       -- CTE containing the ARGS
       arg_input as (select arg_list),
       -- CTE un-nest (flatten) first level of args list to each args set
       arg_sets as 
            (Select row_number() over (order by NULL desc) as arg_id, value as arg_set
             From arg_input, lateral flatten(input => arg_list))
  -- Do something with the Args. e.g. Perform some calculations with the Input arguments            
  Select  arg_id , count(*) array_sz, sum(value)::integer array_sum, array_sum/array_sz::decimal(12,2) array_mean
  From arg_sets, table(flatten(input => arg_set))
  Where is_decimal( value ) or  is_integer( value ) or is_double( value ) -- filter out non-numeric arguments i.e. validate inputs
  Group By arg_id
  $$;  

如果我们提供以下输入参数,这将有效

Select * from table(array_calcs(parse_json('[ [1],
                                              [1,2],
                                              [1,2,3],
                                              [1,2,3,4],
                                              ["A","B"],
                                              ["A",1]
                                            ]')::array));

产生以下内容:

ARG_ID ARRAY_SZ ARRAY_SUM ARRAY_MEAN
1 1 1 1.0
2 2 3 1.5
3 3 6 2.0
4 4 10 2.5
6 1 1 1.0

但请注意。如果您的目标是直接从数据构建参数,而不是在函数调用中硬编码它们,那么您很可能会遇到这个问题:

Create or replace View V_array_calcs_input as 
Select parse_json($1)::array arg_list
from (values ('[[1],[1,2],[1,2,3],[1,2,3,4],["A","B"], ["A",1]'));
Select * 
  from V_array_calcs_input, 
       table(array_calcs(arg_list));

SQL 编译错误:无法评估不受支持的子查询类型

如果您可以在其中任何一个中构建所需的功能逻辑,存储过程或 javascript UDF/UDTF 可能是解决此问题的更好选择。

【讨论】:

以上是关于雪花 SQL udf 的输入列表的主要内容,如果未能解决你的问题,请参考以下文章

雪花,获取两个表之间不匹配列的列表(SQL)

雪花中的 UDF JavaScript 实现

Hive UDF 从列表中生成所有可能的有序组合

雪花不支持的子查询类型无法在 UDF 标量中评估

派斯帕克;用于检查列是不是包含列表元素之一的 UDF

需要从 JAVA UDF 连接雪花表