雪花 json 横向子查询

snowflake json lateral subquery

我在雪花中有以下内容:

create or replace table json_tmp as select column1 as id, parse_json(column2) as c
    from VALUES (1,
                 '{"id": "0x1",
                   "custom_vars": [
                      { "key": "a", "value": "foo" },
                      { "key": "b", "value": "bar" }
                   ] }') v;

基于 FLATTEN docs,我希望将这些变成 table 看起来像这样:

+-------+---------+-----+-----+
| db_id | json_id |  a  |  b  |
+-------+---------+-----+-----+
+-------+---------+-----+-----+
|   1   |   0x1   | foo | bar |
+-------+---------+-----+-----+

这是我试过的查询;它导致 SQL 编译错误:"Object 'CUSTOM_VARS' does not exist."

select json_tmp.id as dbid,
    f.value:id as json_id,
    a.v,
    b.v
from json_tmp,
    lateral flatten(input => json_tmp.c) as f,
    lateral flatten(input => f.value:custom_vars) as custom_vars,
    lateral (select value:value as v from custom_vars where value:key = 'a') as a,
    lateral (select value:value as v from custom_vars where value:key = 'b') as b;

这里的错误到底是什么?有没有更好的方法来进行这种转换?

更新 2019 年 11 月

似乎有一个函数可以做这种事情:

select json_tmp.id as dbid,
    json_tmp.c:id as json_id,
    object_agg(custom_vars.value:key, custom_vars.value:value):a as a,
    object_agg(custom_vars.value:key, custom_vars.value:value):b as b
from
    json_tmp,
    lateral flatten(input => json_tmp.c, path => 'custom_vars') custom_vars
group by json_tmp.id

原始答案 2017 年 9 月

以下查询似乎有效:

select json_tmp.id as dbid,
    json_tmp.c:id as json_id,
    a.value:value a,
    b.value:value b
from
    json_tmp,
    lateral flatten(input => json_tmp.c, path => 'custom_vars') a,
    lateral flatten(input => json_tmp.c, path => 'custom_vars') b
where a.value:key = 'a' and b.value:key = 'b'
;

我宁愿在子查询中过滤而不是在连接中过滤,所以我仍然有兴趣查看其他答案。

注意 - 您的解决方案实际上不执行任何连接 - 展平是一个 "streaming" 操作,它 "explodes" 输入,然后选择它想要的行。如果数据中只有 2 个属性,它应该相当快。但是,如果不这样做,可能会导致不必要的数据爆炸(例如,如果您有 1000 多个属性)。

最快的解决方案取决于您的数据的确切结构,以及您对输入的假设。例如,如果您知道 'a' 和 'b' 始终按此顺序,您显然可以使用

select 
    id as db_id, 
    c:id, 
    c:custom_vars[0].value, 
    c:custom_vars[1].value 
from json_tmp;

如果您知道 custom_vars 总是 2 个元素,但顺序未知,您可以这样做,例如

select 
    id as db_id, 
    c:id, 
    iff(c:custom_vars[0].key = 'a', c:custom_vars[0].value, c:custom_vars[1].value), 
    iff(c:custom_vars[0].key = 'b', c:custom_vars[0].value, c:custom_vars[1].value) 
from json_tmp;

如果 custom_vars 的大小未知,您可以创建一个像 extract_key(custom_vars, key) 这样的 JavaScript 函数来迭代 custom_vars 和 return value 用于找到 key(或者例如 null<empty_string>,如果未找到)。

希望这对您有所帮助。如果不是,请提供有关您的问题(数据等)的更多详细信息。