Search code examples
sqlsubquerysnowflake-cloud-data-platformuser-defined-functions

Snowflake SQL UDF - Unsupported Subquery Error


I am creating a Snowflake SQL UDF. I keep running into SQL compilation error: Unsupported subquery type cannot be evaluated. I have tried to do several things to go around the issue, this being my latest try.

How can I make this break out of the subquery'ing error?

The UDF should allow one to input their preferred year. Thinking to create a solution by if a year is not provided, the default would be the present year.

create or replace function new_value(PRICE float, TYPE varchar, YR_CREATED int, YEAR int)

returns float

as
$$

 
with AGE_OF_PRODUCT as (
    select any_value((YEAR - YR_CREATED)) as AGE ),



  FORMULA as (
    select any_value(AGE) as AGE,
    any_value(case
        when AGE <= 1 then 1
        else 2
    end) as FUNCTION
    from AGE_OF_PRODUCT

  )
  
  select
     any_value(case
        when F.FUNCTION = 1 then (PRICE - (PRICE * R.R1))
        else (PRICE * (1 - (R.R1))) * pow((1-(R.R2)), ((F.AGE - YR_CREATED)-1))
    end) as VALUE
  from FORMULA as F, RATES as R
  where TYPE = R.TYPE_OF_PRODUCT

  
                                      
$$;

Solution

  • So the main problem is you are likely using the function like:

    select v.*,
        new_value(v.price, v.type, v.yr_create, v.year) as awesome
    from table_with_values as v
    

    also your UDF can be rewritten as it stands as:

    create or replace function new_value(
        PRICE float, 
        TYPE varchar, 
        YR_CREATED int, 
        YEAR int)
    returns float
    as
    $$
    
        select
            YEAR - YR_CREATED as age,
            case age <= 1
                when true then (PRICE - (PRICE * r.r1))
                else (PRICE * (1 - (r.r1))) * pow((1-(r.r2)), ((age - YR_CREATED)-1))
            end as value
        from rates as r
        where TYPE = r.type_of_product
                          
    $$;
    

    but if we move the join to rates outside the UDF

    create or replace function new_value(
        PRICE float, 
        YR_CREATED int, 
        YEAR int,
        rate1 float,
        rate2 float)
    returns float
    as
    $$
        select
            case (YEAR - YR_CREATED) <= 1
                when true then (PRICE - (PRICE * r.r1))
                else (PRICE * (1 - (rate1))) * pow((1-(rate2)), (((YEAR - YR_CREATED) - YR_CREATED)-1))
            end as value;                     
    $$;
    

    then we can call it like:

    select v.*,
        new_value(v.price, v.yr_create, v.year, r.r1, r.r2) as awesome
    from table_with_values as v
    join rates as r 
        on v.type = r.type_of_product