简体   繁体   English

Snowflake:十进制或 null 输入到 function 导致“不支持的子查询类型”

[英]Snowflake: Decimal or null input to function results in "Unsupported subquery type"

Given the following function:鉴于以下 function:

CREATE
OR REPLACE FUNCTION myfunction(a float, b float, c float)
RETURNS float AS
$$ 
select sum(1/(1+exp(-(series - c)/4)))
from (
    select (a + ((row_number()) over(order by 0))*1) series
    from table(generator(rowcount => 10000)) x
    qualify series <= b
)
$$;

I get all the expected results when executing the following queries:执行以下查询时,我得到了所有预期结果:

select
    myfunction(1, 10, 1);
select
    myfunction(1, 100, 1);
select
    myfunction(1, 10, 1.1);
select
    myfunction(0, 1, 89.87);
select
    myfunction(0, 1, null);

However when I run the following query:但是,当我运行以下查询时:

select
    myfunction(a, b, c)
from
    (
        select
            1 as a,
            10 as b,
            1.1 as c
        union
        select
            0 as a,
            1 as b,
            null as c
    );

I get an error:我得到一个错误:

"Unsupported subquery type cannot be evaluated". “无法评估不支持的子查询类型”。

While this query does work:虽然此查询确实有效:

select
    a, b, myfunction(a, b, c)
from
    (
        select
            1 as a,
            10 as b,
            1 as c
        union
        select
            1 as a,
            100 as b,
            1 as c 
    );

Why can't Snowflake handle null or decimal numbers in the 'c' column when I input multiple rows while individual rows weren't a problem?为什么当我输入多行时 Snowflake 不能处理 null 或“c”列中的十进制数字,而单行不是问题? And how can this function be rewritten to be able to handle these cases?以及如何重写这个 function 来处理这些情况?

Weird one.奇怪的一个。 Can you try selecting from the subquery and running it through a cast?您可以尝试从子查询中选择并通过强制转换运行它吗?

Like this:像这样:

select a, b, c
from
(select cast(a as float) as a, cast(b as float) as b, cast(c as float) as c from 
    (
        select
        1 as a,
        10 as b,
        1 as c
    union
        select
        1 as a,
        100 as b,
        null as c 
    ) as t) as x

SQL UDFs are converted to subqueries (for now), and if Snowflake can not determine the data type returned from these subqueries, you get the "Unsupported subquery" error. SQL UDF 被转换为子查询(目前),如果 Snowflake 无法确定从这些子查询返回的数据类型,您将收到“不支持的子查询”错误。 The issue is not about decimals or null. The issue is A and C variables (which are used in SUM()) contain different values.问题与小数或 null 无关。问题是 A 和 C 变量(在 SUM() 中使用)包含不同的值。 For example, the following ones work:例如,以下的工作:

select
    myfunction(a, b, c )
from
    (
        select
            1 as a,
            1 as b,
            1.1 as c
        union
        select
            1 as a,
            100 as b,
            1.1  as c
    );

select
    myfunction(a, b, c )
from
    (
        select
            1 as a,
            1 as b,
            null as c
        union
        select
            1 as a,
            100 as b,
            null  as c
    );

You may hit these kinds of errors when you try to write complex functions with SQL UDFs.当您尝试使用 SQL UDF 编写复杂函数时,您可能会遇到这些类型的错误。 Sometimes rewriting them can help, but I don't see a way for this one.有时重写它们会有所帮助,但我看不出有什么办法。 As a workaround, you may re-write it in JavaScript because JS UDFs are not converted to subqueries:作为解决方法,您可以在 JavaScript 中重写它,因为 JS UDF 不会转换为子查询:

CREATE
OR REPLACE FUNCTION myfunction(a float, b float, c float)
RETURNS float 
language javascript AS
$$ 
  var res = 0.0;
  
  for (let series = A + 1; series <= B; series++) {
      res += (1/(1+Math.exp(-(series - C)/4))); 
  }
 
  return res;
$$; 

According to my tests, the above UDF returns the same result as the SQL version, and it doesn't hit "Unsupported subquery" error.根据我的测试,上述 UDF 返回与 SQL 版本相同的结果,并且没有出现“不支持的子查询”错误。

In the end implementing it as a python function allowed for also handling all the edge cases:最后将其实现为 python function 还允许处理所有边缘情况:

CREATE
    OR REPLACE FUNCTION myfunction(a float, b float, c float)
  returns float
  language python
  runtime_version=3.8
  handler='compute'
as
$$
def compute(a, b, c):
    
    import math 

    if b < a:
        return None

    if c is None:
        return None
    
    res = []
    step_size = 1
    
    it = a
    while it < b:
        res.append(it)
        it += step_size
    
    res = sum([1/(1+math.exp(-1*(i-c)/4)) for i in res])
    
    return res
$$;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM