使用函数时雪花不支持的子查询
Posted
技术标签:
【中文标题】使用函数时雪花不支持的子查询【英文标题】:Snowflake unsupported subquery when using function 【发布时间】:2021-05-04 23:54:24 【问题描述】:这是我创建的函数:
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)
';
我使用的是 ROW_NUMBER 函数,因为 RATE_DATE 字段实际上是日期时间,因此每个日期有多个记录。
当我自己调用该函数时,它工作正常。但是,当我尝试在视图中使用它时,会出现不支持的子查询类型错误。没有它,视图工作正常。谁能想到我可以做些什么来修复错误或通过重写查询来解决它?
编辑 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
错误信息: SQL 错误 [2031] [42601]:SQL 编译错误: 无法评估不受支持的子查询类型
【问题讨论】:
我知道雪花错误消息不是很有帮助,但您能否分享一下您的视图是什么样的以及确切的错误消息是什么? 【参考方案1】:错误是相关子查询,不支持(除了一些小玩具示例)
但基本形式是
SELECT a.a
(select b.b from b where b.a = a.a order by b.y limit 1)
FROM a;
对于每一行,子查询都会在另一个表上运行以获取值。在其他数据库中做了很多技巧来使这个“工作”,但实际上每一行都有工作。 Snowflake 不会对每行操作进行类型化。
好消息是其他模式实际上是相同的,雪花确实支持,这两种模式实际上是相同的,使用 CTE 或加入子选择,这是同一件事。
所以上面变成:
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
所以我们首先处理/塑造来自其他/子表的“所有记录”,并且我们只保留具有我们想要的计数/形状的行,然后加入该结果。是非常可并行化的,所以性能很好。 Snowflake 没有为您自动翻译子查询的原因是,它很容易出错,而且他们目前正在那里进行开发工作,致力于研究根本不存在的功能等,并且可以通过以下方式重写你,只要你了解你的模型。
【讨论】:
将此标记为答案,因为它与我最终所做的非常相似。感谢大家的帮助。【参考方案2】:如果将其移至FROM
子句会怎样?我将其表述为:
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;
请注意,我更改了参数的名称,因此它们更明显是输入参数。
【讨论】:
不过,我做不到 MAX(er.rate)。 MAX(如果有)必须在 er.rate_date 上。否则我会得到最大的利率,而不是最近的。 @MikeCaputo 。 . .子查询只返回一行,所以MAX()
并没有真正做任何事情。只保证结果集中只有一行。
这样做我得到了同样的不受支持的子查询类型错误。
@MikeCaputo 。 . .我在想将逻辑移到 FROM
子句可能会解决问题。以上是关于使用函数时雪花不支持的子查询的主要内容,如果未能解决你的问题,请参考以下文章