简体   繁体   English

使用 function 时雪花不支持的子查询

[英]Snowflake unsupported subquery when using function

This is the function I created:这是我创建的 function:

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.我正在使用 ROW_NUMBER function 因为 RATE_DATE 字段实际上是日期时间,因此每个日期有多个记录。

When I call the function by itself, it works fine.当我自己调用 function 时,它工作正常。 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编辑 1:查看代码和确切的错误消息

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错误消息:SQL 错误 [2031] [42601]:SQL 编译错误:无法评估不支持的子查询类型

What if you move this to the FROM clause?如果你把它移到FROM子句怎么办? I would phrase this as:我将其表述为:

SELECT COALESCE(MAX(er.rate), 1)
FROM (SELECT er.*
      FROM CONNECTORS.COUPA.EXCHANGE_RATE er
      WHERE er.FROM_CURRENCY_ID = in_from_curr_id AND
            er.TO_CURRENCY_ID = in_to_curr_id AND
            DATE(er.RATE_DATE) = in_date
      ORDER BY RATE_DATE DESC
      LIMIT 1
     ) er;

Notice that I changed the names of the parameters so they are more obviously input parameters.请注意,我更改了参数的名称,因此它们更明显是输入参数。

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. Snowflake 不会为每行操作键入类型。

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.好消息是其他模式实际上是相同的,雪花确实支持,这两种模式实际上是相同的,使用 CTE 或加入子选择,这是同一件事。

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. Snowflake 没有为您自动翻译子查询的原因是,它很容易出错,而且他们目前正在那里进行开发工作,致力于研究根本不存在的功能等,并且可以通过以下方式重写你,如果你了解你的 model。

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

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