Skip to content
Advertisement

Snowflake unsupported subquery when using function

This is the function I created:

CREATE OR REPLACE FUNCTION NS_REPORTS.AP."COUPA_GET_EXCH_RATE"("from_curr_id" NUMBER(38,0), "to_curr_id" NUMBER(38,0), "date" DATE)
RETURNS FLOAT
LANGUAGE SQL
AS '
    SELECT 
        COALESCE((
            SELECT 
                RATE 
            FROM 
                (
                    SELECT
                        ROW_NUMBER() OVER (PARTITION BY DATE(RATE_DATE) ORDER BY RATE_DATE DESC) ROW_NUM
                        , RATE
                    FROM
                        CONNECTORS.COUPA.EXCHANGE_RATE
                    WHERE
                        FROM_CURRENCY_ID = from_curr_id
                        AND TO_CURRENCY_ID = to_curr_id
                        AND DATE(RATE_DATE) = date
                ) R
            WHERE
                ROW_NUM = 1
        ), 1)
';

I’m using the ROW_NUMBER function because the RATE_DATE field is actually datetime and so there are multiple records per date.

When I call the function by itself, it works fine. However, when I try to use it in a view, I get the unsupported subquery type error. The view works fine without it. Can anyone think of what I can do to either fix the error or work around it by rewriting the query?

EDIT 1: View code and exact error message

CREATE OR REPLACE VIEW COUPA_REQUISITION
AS
SELECT
    RH.ID REQ_NUM
    , RL.LINE_NUM REQ_LINE_NUM
    , OH.PO_NUMBER 
    , REPLACE(REPLACE(OH.CUSTOM_FIELDS:"legacy-po-number", '"', ''), '.0', '') LEGACY_PO_NUMBER
    , S."NAME" SUPPLIER
    , OH.STATUS 
    , UR.FULLNAME REQUESTED_BY
    , UC.FULLNAME CREATED_BY
    , OL.RECEIVED
    , DATE(RH.SUBMITTED_AT) ORDER_DATE
    , DATE(RH.NEED_BY_DATE) NEEDED_BY_DATE
    , RL."DESCRIPTION" ITEM
    , CAST(NULL AS VARCHAR) CHART_OF_ACCOUNTS
    , REPLACE(OH.CUSTOM_FIELDS:"purchase-type", '"', '') PURCHASE_TYPE
    , COM."NAME" COMMODITY
    , ACT.NS_SUB_NAME SUBSIDIARY
    , ACT.NS_ACCT_NAME_FULL "ACCOUNT"
    , ACT.NS_DEPT_NAME_FULL DEPARTMENT
    , ACT.NS_L3_DEPT_NAME L3_DEPARTMENT
    , ACT.NS_LOC_NAME "LOCATION"
    , RL.QUANTITY QTY
    , OL.LINE_NUM ORDER_LINE_NUM
    , RL.TOTAL * NS_REPORTS.AP.COUPA_GET_EXCH_RATE(RL.CURRENCY_ID, 1, DATE(RH.SUBMITTED_AT)) LINE_TOTAL
    , RL.TOTAL - OL.INVOICED UNINVOICED_AMOUNT
    , OL.INVOICED INVOICED_TOTAL
    , RLSUM.TOTAL TOTAL
    , REPLACE(IL.CUSTOM_FIELDS:"amortization-schedule"."name", '"', '') AMORTIZATION_SCHEDULE
    , CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-start-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-start-date", '"', '')) ELSE NULL END AMORTIZATION_START_DATE
    , CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-end-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-end-date", '"', '')) ELSE NULL END AMORTIZATION_END_DATE
    , CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-start-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-start-date", '"', '')) ELSE NULL END CONTRACT_START_DATE
    , CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-end-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-end-date", '"', '')) ELSE NULL END CONTRACT_END_DATE
FROM 
    CONNECTORS.COUPA.REQUISITION_HEADER RH
    JOIN CONNECTORS.COUPA.REQUISITION_LINE RL ON RL.REQUISITION_HEADER_ID = RH.ID
    JOIN NS_REPORTS.AP.COUPA_ACCOUNT ACT ON ACT.COUPA_ACCT_ID = RL.ACCOUNT_ID
    JOIN CONNECTORS.COUPA."USER" UR ON UR.ID = RH.REQUESTED_BY_ID 
    JOIN CONNECTORS.COUPA."USER" UC ON UC.ID = RH.CREATED_BY_ID 
    JOIN (
        SELECT
            REQUISITION_HEADER_ID 
            , SUM(TOTAL) TOTAL
        FROM
            CONNECTORS.COUPA.REQUISITION_LINE 
        GROUP BY
            REQUISITION_HEADER_ID 
    ) RLSUM ON RLSUM.REQUISITION_HEADER_ID = RH.ID
    LEFT JOIN CONNECTORS.COUPA.ORDER_LINE OL ON OL.ID = RL.ORDER_LINE_ID 
    LEFT JOIN CONNECTORS.COUPA.ORDER_HEADER OH ON OH.ID = OL.ORDER_HEADER_ID 
    LEFT JOIN CONNECTORS.COUPA.COMMODITY COM ON COM.ID = OL.COMMODITY_ID  
    LEFT JOIN CONNECTORS.COUPA.SUPPLIER S ON S.ID = OH.SUPPLIER_ID 
    LEFT JOIN CONNECTORS.COUPA.INVOICE_LINE IL ON IL.ORDER_LINE_ID = OL.ID 

Error message: SQL Error [2031] [42601]: SQL compilation error: Unsupported subquery type cannot be evaluated

Advertisement

Answer

The error is a correlated subquery and the are not supported (beyond some tiny toy examples)

But the basic form is

SELECT a.a
       (select b.b from b where b.a = a.a order by b.y limit 1)
FROM a;

in effect for each row, a sub-query is run on another table to get a value. There are many tricks done in other DB’s to make this “work” but in effect there is work done on each row. Snowflake does not types of for each row operations.

The good news is there are other patterns that are effectively the same, that snowflake does support, the two patterns are really the same use a CTE or join to a sub-select which is the same thing.

so the above becomes:

WITH subquery AS (
    SELECT b.a, b.b FROM b
    QUALIFY row_number() over (partition by b.a order by b.y) = 1
)
SELECT a.a
    sq.b
FROM a
JOIN subquery AS sq 
    ON sq.a = a.a

So we first process/shape “all records” from the other/sub table, and we only keep the rows that have the count/shape we want, and then join to that result. The is very parallelizable, so performs well. The reason Snowflake does not auto translate a sub-query for you, is it rather easy to get it wrong, and they presently are spending there development efforts working on features that do not exist at all, etc etc, and it can be rewritten by you, given you understand your model.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement