【问题标题】:Join on recursive CTE in snowflake disobeys where clause在雪花中加入递归 CTE 不服从 where 子句
【发布时间】:2021-12-23 04:17:35
【问题描述】:

考虑以下观点和 CTE:

CREATE OR REPLACE VIEW SubSet (Id)
AS (
          SELECT '123'
UNION ALL SELECT '456'
UNION ALL SELECT 'x'
)

CREATE OR REPLACE VIEW MainSet (Id)
AS (
          SELECT 123
UNION ALL SELECT 456
UNION ALL SELECT 789
)


WITH myCte (id, cnt) AS
(
  SELECT id, 1 AS cnt FROM SubSet
  UNION ALL
  SELECT id
  ,cnt + 1 FROM myCte WHERE cnt < 4 AND id <> 'x'
)
SELECT *
FROM MainSet ms
JOIN (
  SELECT id FROM myCte WHERE id <> 'x'
) X ON ms.id = X.id

请注意,“x”在 CTE 的递归部分和 CTE 的子查询中都被过滤掉了。

这昨天奏效了。但截至今天,它以“无法识别数值'x'”失败。

如果我删除递归部分,它不会失败:

WITH myCte (id, cnt) AS
(
  SELECT id, 1 AS cnt FROM SubSet
  --UNION ALL
  --SELECT id
  --,cnt + 1 FROM myCte WHERE cnt < 4 AND id <> 'x'
)
SELECT *
FROM MainSet ms
JOIN (
  SELECT id FROM myCte WHERE id <> 'x'
) mc ON ms.id = mc.id

查询被过滤后如何匹配“x”?它似乎只在使用递归 CTE 时适用。

【问题讨论】:

  • 不知道为什么有一天你会失败,但我可以说递归种子(你的 myCte 定义中最顶层的查询)应该包含过滤器,否则 x 会去显示在您的结果中。就您而言,它不应该出现在子查询的过滤器中,但肯定会出现在 myCte 的输出中。
  • 你是对的。但是我最初的 CTE 更复杂,并且我没有递归种子中的“x”值。

标签: snowflake-cloud-data-platform common-table-expression


【解决方案1】:

最终,我相信问题源于最终 SELECT 查询中的 ON 子句。 Snowflake 正在尝试对 X.id 上的数字进行隐式强制转换以使连接发生,但它失败了。

我想有一个查询优化步骤正在发生,它采用 ON 谓词并在执行路径中比 WHERE 子句中的谓词更快地推送它。对我来说,这感觉像是 Snowflake 中的一个错误,但由于 SQL 稍显草率和允许隐式转换发生的不太干净的数据而加剧了这个错误。

您可以通过将 ON 标准更改为:

ON cast(ms.id as string) = X.id

这可确保 Snowflake 不必决定将您的 ms.id 转换为字符串或将您的 X.id 转换为可能会做出错误选择的数字。

工作示例(注意在此示例中删除演员表将导致错误再次弹出):

WITH SubSet (Id)
AS (
    SELECT '123'
    UNION ALL SELECT '456'
    UNION ALL SELECT 'x'
)
,MainSet (Id)
AS (
    SELECT 123
    UNION ALL SELECT 456
    UNION ALL SELECT 789
)
,myCte (id, cnt) AS
(
  SELECT id, 1 AS cnt FROM SubSet
  UNION ALL
  SELECT id
      ,cnt + 1 
  FROM myCte 
  WHERE cnt < 4 AND id <> 'x'
)   
SELECT *
FROM MainSet ms
  JOIN (
    SELECT id FROM myCte WHERE id <> 'x'
  ) X ON cast(ms.id as string) = X.id;

【讨论】:

  • 大概就是这样。您的解决方案有效,尽管在我原来的解决方案中我用横向扁平化替换了我的 CTE。 (但是我怀疑我原来的 SQL 是否草率 :) 我确实有一个 CAST 但谁知道过滤器会突然被省略?虽然 try_to_number 会更好。)
  • 我并不是要建议你写草率的 sql,只是 SQL 的意思是非常明确的,所以将字符串类型连接到数字类型并希望数据库做出正确的决定,完全清楚将不得不强制转换一个或另一个来完成连接,为该数据库留下做出错误决定的空间。最终,这里真正的垃圾是雪花的。 1) 决定将第一个术语转换为第二个术语,或者字符串到数字而不是数字到字符串感觉很愚蠢和错误。 2) 将 ON 谓词放在子 where 谓词之前的谓词下推。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 2021-06-15
相关资源
最近更新 更多