3

我在雪花中有以下内容:

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文档,我希望将它们变成如下所示的表格:

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

这是我尝试过的查询;它导致 SQL 编译错误:“对象 'CUSTOM_VARS' 不存在。”

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;

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

4

2 回答 2

1

注意 - 您的解决方案实际上并不执行任何连接 - flatten 是一个“流”操作,它“分解”输入,然后选择它想要的行。如果数据中只有 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 的大小未知,您可以创建一个类似的 JavaScript 函数extract_key(custom_vars, key),该函数将遍历custom_vars并返回value找到的key(或例如null<empty_string>如果未找到)。

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

于 2017-09-18T04:33:00.100 回答
0

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'
;

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

于 2017-09-15T19:19:20.297 回答