jsonsnowflake-cloud-data-platform

How do I expand a JSON string which is stored inside a column in a Snowflake table?


I have a table in Snowflake that looks something like this:

+------+------+------+------------------------------------------------------------------+
| Col1 | Col2 | Col3 |                               Col4                               |
+------+------+------+------------------------------------------------------------------+
|    1 | foo  |   32 | [{"id":"1", "category":"black"}]                                 |
|    2 | bar  |   22 | [{"id":"1", "category":"black"}, {"id":"4", "category":"white"}] |
|    3 | smeg |    2 | null                                                             |
+------+------+------+------------------------------------------------------------------+

I would like to transform the data into another table that looks like this:

+------+------+------+------+----------+
| Col1 | Col2 | Col3 |  id  | category |
+------+------+------+------+----------+
|    1 | foo  |   32 | 1    | black    |
|    2 | bar  |   22 | 1    | black    |
|    2 | bar  |   22 | 4    | white    |
|    3 | smeg |    2 | null | null     |
+------+------+------+------+----------+

I've done this in SQL Server before using JSON_VALUE and OPENJSON but I am having trouble trying to find a Snowflake equivalent.


Solution

  • A correction to the above answer, Nulls need to be explicitly handled for category.

    Lateral flatten alone would not consider NULLs, you can use OUTER => TRUE or use UNION with condition WHERE Col4 IS NULL.

    OUTER documentation

    If FALSE, any input rows that cannot be expanded, either because they cannot be accessed in the path or because they have zero fields or entries, are completely omitted from the output.

    If TRUE, exactly one row is generated for zero-row expansions (with NULL in the KEY, INDEX, and VALUE columns)

    SELECT 
    col1,col2,col3,flatten.value:id::STRING AS id,
    flatten.value:category::STRING AS category
    FROM 
    test1 t,
    LATERAL FLATTEN(input => t.col4,OUTER => TRUE) flatten 
    ;
    

    Output

    enter image description here