JPlanken
JPlanken

Reputation: 63

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

Given the following 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? And how can this function be rewritten to be able to handle these cases?

Upvotes: 1

Views: 129

Answers (3)

JPlanken
JPlanken

Reputation: 63

In the end implementing it as a python function allowed for also handling all the edge cases:

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
$$;

Upvotes: 0

Gokhan Atil
Gokhan Atil

Reputation: 10039

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. The issue is not about decimals or null. The issue is A and C variables (which are used in SUM()) contain different values. 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. 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:

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.

Upvotes: 1

DaveWuzHere
DaveWuzHere

Reputation: 255

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

Upvotes: 0

Related Questions