Snowflake JSON 尝试获取不同值时出现未知关键字错误

Snowflake JSON unknown keyword error when trying to get distinct values

我在 Snowflake 中有一个 table,其中一个名为 'value' 的字段有时是纯文本有时 JSON,该字段在 Snowflake[=20= 中存储为字符串]

我创建此视图是为了仅获取具有 Json 格式的行

CREATE OR REPLACE VIEW tmp_events AS
    SELECT PARSE_JSON(value) as json_data,
           id
    FROM SessionEvent 
    WHERE session_event_type_id=7;

然后我将行展平以创建一个新字段

CREATE OR REPLACE VIEW tmp_events_step2 AS
     SELECT id,
            json_data:meta:selected::string AS choice
         from tmp_events ,
     LATERAL FLATTEN(input => tmp_events.json_data)
     WHERE choice IS NOT NULL

一切运行到现在都很好,我可以从这两个视图预览数据,没有错误,我得到了我期待的结果。

当我尝试从 choice 中获取不同的值时出现错误

 SELECT DISTINCT choice from tmp_events_step2;

Error parsing JSON: unknown keyword "brain", pos 6

这个名字 Brain 似乎来自我最初的 table 没有 WHERE 声明。

如果我运行没有DISTINCT的查询就没有错误。

我在尝试调试时注意到的一件奇怪的事情:当我在 tmp_events_step2 中设置一个限制时,代码再次正常工作,即使我设置的限制大于 [=43] 中的行数=]

CREATE OR REPLACE VIEW tmp_events_step2 AS
     SELECT id,
            json_data:meta:selected::string AS choice
         from tmp_events ,
     LATERAL FLATTEN(input => tmp_events.json_data)
     WHERE choice IS NOT NULL
     LIMIT 10000000;
SELECT DISTINCT choice from tmp_events_step2;

有什么收获?为什么它只对限制有效?

请针对此问题提交支持案例。

对此的非常简单的答案是内置函数 TRY_PARSE_JSON()

呃,不是。您似乎对查询优化器有问题,可能会执行不正确的谓词下推。防止优化器这样做的一种方法是使用安全视图选项:

CREATE SECURE VIEW tmp_events_step2 ...

并提交支持请求...

我们在两年前报告了这个错误,他们说他们不会修复,因为通过在 运行 之前提升 JSON 访问权限,WHERE 子句中的过滤器使强制转换 valid/safe,影响性能。

create table variant_cast_bug(num number, var variant);

insert into variant_cast_bug
    select column1 as num, parse_json(column2) as var
    from values (1, '{"id": 1}'), 
            (1, '{"id": 2}'),
            (2, '{"id": "text"}')
            v;

select * from variant_cast_bug;
select var:id from variant_cast_bug;
select var:id from variant_cast_bug where num = 1;
select var:id::number from variant_cast_bug where num = 1; -- <- broken
select TRY_TO_NUMBER(var:id) from variant_cast_bug where num = 1; -- <- works

有时你可以嵌套 select 它会起作用,然后你可以在它周围添加另一个 SELECT 层,并进行一些聚合,成本再次爆炸。

正如 Hans 提到的那样,仅有的两个安全解决方案是 SERCURE VIEW,但这是一个性能噩梦。 或者了解这个问题,用TRY_TO_NUMBER或者它的朋友。

当时情况变得更糟,因为 JSON 布尔值无法传递给 TRY_TO_BOOLEAN..

有一次我们被这个问题困扰是在雪花发布之后,当时已经 运行 一年的代码开始出现这个错误,因为它足够复杂,提升没有影响,并且然后在发布后它做到了。这是 Snowflake 相当敏感的地方,然后回滚了版本,我们将 TRY_TO 放在已经工作的 SQL 上,只是为了安全起见。