2017-09-15 69 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' 
; 

我會在一個子查詢,而不是在加入而過濾,所以我仍然希望看到其他的答案。