2017-09-15 67 views
1

的雪花,我有以下:基于FLATTEN docs雪花JSON横向子查询

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; 

,我希望把这些到表看起来像这样:

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

这里的错误究竟是什么?有没有更好的方法来做这种转变?

回答

0

注意 - 您的解决方案实际上并未执行任何连接 - 拼合是一种“流式”操作,它会“爆炸”输入,然后选择所需的行。如果数据中只有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>如果没有找到)。

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

+0

这是非常有用的,我没有意识到我可以在javascript中编写UDF。我怀疑这对我来说是最好的解决方案;该数组将有五个自定义变量。 – jsharp

+0

如果我使用这样的UDF:var obj = {}; customData.forEach((item)=> {obj [item.key] = item.value;});返回obj; ',有什么办法,除了IMMUTABLE(根据文档不能保证memoization),以确保它只被调用一次?想要做一些类似'select db_id as id,c:id,custom_vars:a,custom_vars:b' – jsharp

+0

这个系统通常足够聪明,可以优化常见的子表达式,所以如果你像'select my_func(C):a ,my_func(C):b它应该只调用一次。 –

0

下面的查询似乎工作:

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

我会在一个子查询,而不是在加入而过滤,所以我仍然希望看到其他的答案。