2015-05-12 45 views
2

我有一個紅移表看起來像這樣紅移JSON數組的元素:返回在單獨行

id | metadata 
--------------------------------------------------------------------------- 
1 | [{"pet":"dog"},{"country":"uk"}] 
2 | [{"pet":"cat"}] 
3 | [] 
4 | [{"country":"germany"},{"education":"masters"},{"country":"belgium"}] 
  • 所有的數組元素只有一個領域。
  • 無法保證某個特定字段在任何數組元素中都有特徵。
  • 字段名稱可以在陣列中重複
  • 數組元素可以是任何順序

我想回去的表看起來像這樣:

id | field | value 
------------------------ 
1 | pet  | dog 
1 | country | uk 
2 | pet  | cat 
4 | country | germany 
4 | education | masters 
4 | country | belgium 

我然後可以將其與我對其餘輸入表的查詢結合起來。

我已經嘗試過使用Redshift JSON函數,但是沒有能夠編寫函數/在Redshift中使用循環/變量,我真的看不到一種方法來做到這一點!

請讓我知道,如果我可以澄清其他任何事情。

回答

3

感謝這個靈感blog post,我已經能夠制定一個解決方案。這是:

  1. 創建一個查找表,以有效地「迭代」每個數組的元素。此表中的行數等於或大於數組元素的最大數量。比方說,這是4(它可以使用SELECT MAX(JSON_ARRAY_LENGTH(metadata)) FROM input_table計算):

    CREATE VIEW seq_0_to_3 AS 
        SELECT 0 AS i UNION ALL          
        SELECT 1 UNION ALL 
        SELECT 2 UNION ALL  
        SELECT 3   
    ); 
    
  2. 從這一點,我們可以爲每個JSON元素創建一個行:

    WITH exploded_array AS (                   
        SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json 
        FROM input_table, seq_0_to_3 AS seq 
        WHERE seq.i < JSON_ARRAY_LENGTH(metadata) 
    ) 
    SELECT * 
    FROM exploded_array; 
    

    生產:

    id | json 
    ------------------------------ 
    1 | {"pet":"dog"} 
    1 | {"country":"uk"} 
    2 | {"pet":"cat"} 
    4 | {"country":"germany"} 
    4 | {"education":"masters"} 
    4 | {"country":"belgium"} 
    
  3. 但是,我需要提取字段名稱/值。因爲我看不出有什麼方法來提取使用紅移的功能有限JSON字段名,我會做這個使用正則表達式:

    WITH exploded_array AS (                      
        SELECT id, JSON_EXTRACT_ARRAY_ELEMENT_TEXT(metadata, seq.i) AS json 
        FROM input_table, seq_0_to_3 AS seq 
        WHERE seq.i < JSON_ARRAY_LENGTH(metadata) 
    ) 
    SELECT id, field, JSON_EXTRACT_PATH_TEXT(json, field) 
    FROM (
        SELECT id, json, REGEXP_SUBSTR(json, '[^{"]\\w+[^"]') AS field 
        FROM exploded_array 
    ); 
    
1

沒有爲CREATE VIEW seq_0_to_3通用版本。我們稱之爲CREATE VIEW seq_0_to_n。這可以通過生成

SELECT row_number() over (
         ORDER BY TRUE)::integer - 1 
FROM <insert_large_enough_table> LIMIT <number_less_than_table_entries>; 

這有助於生成大序列作爲視圖。