Flatten nested JSON in snowflake

让人想犯罪 __ 提交于 2021-01-29 07:31:19

问题


this is an example of a JSON (it can be more, or less, types and/or values. I want to end up with (order not important):

Countries, IC Countries, ES Countries, SE Countries, GB Countries, US Categories, film-chat

JSON

{
  "list": [
    {
      "element": {
        "comparison": "anyOf",
        "logical": "and",
        "type": "Countries",
        "value": {
          "list": [
            {
              "element": "IC"
            },
            {
              "element": "ES"
            },
            {
              "element": "SE"
            },
            {
              "element": "GB"
            },
            {
              "element": "US"
            }
          ]
        }
      }
    },
    {
      "element": {
        "comparison": "anyOf",
        "logical": "and",
        "type": "Categories",
        "value": {
          "list": [
            {
              "element": "film-chat"
            }
          ]
        }
      }
    }
  ]
}

What I've tried so far, probably iteration 17: Can't past more code apparently... Need more details.


回答1:


Are you using FLATTEN() documented at https://docs.snowflake.com/en/sql-reference/functions/flatten.html?

We need more to go on, but you'll likely end up with something like:

with tbl as (select parse_json($1) json from values ('{"list":[{"element":{"comparison":"anyOf","logical":"and","type":"Countries","value":{"list":[{"element":"IC"},{"element":"ES"},{"element":"SE"},{"element":"GB"},{"element":"US"}]}}},{"element":{"comparison":"anyOf","logical":"and","type":"Categories","value":{"list":[{"element":"film-chat"}]}}}]}'))
select *
from tbl,
  lateral flatten(json:list) list_l1 ,
  lateral flatten(list_l1.value:element) element_l1,
  lateral flatten(element_l1.value:list, OUTER => TRUE) list_l2 ,
  lateral flatten(list_l2.value:element, OUTER => TRUE) element_l2



回答2:


A while ago I actually wrote a piece of documentation around that:

https://community.snowflake.com/s/article/Dynamically-extract-multi-level-JSON-object-using-lateral-flatten

It allows for dynamically extracting all fields up to 4th level of nesting (and you can always add more) and then you can sort them the way you need using regular selects.




回答3:


If we assume that we have a table defined (and populated) as follows:

CREATE OR REPLACE TEMPORARY TABLE MY_TABLE (
  MY_DICT  VARIANT
)
AS
  SELECT PARSE_JSON($1) AS MY_DICT
    FROM VALUES ($$
  {
    "list": [
      {
        "element": {
          "comparison": "anyOf",
          "logical": "and",
          "type": "Countries",
          "value": {
            "list": [
              {
                "element": "IC"
              },
              {
                "element": "ES"
              },
              {
                "element": "SE"
              },
              {
                "element": "GB"
              },
              {
                "element": "US"
              }
            ]
          }
        }
      },
      {
        "element": {
          "comparison": "anyOf",
          "logical": "and",
          "type": "Categories",
          "value": {
            "list": [
              {
                "element": "film-chat"
              }
            ]
          }
        }
      }
    ]
  }
  $$)
;

Then we can use this query to return the information you specified:

SELECT LISTAGG(F1.VALUE:"element":"type"::VARCHAR || ', ' || F2.VALUE:"element"::VARCHAR, ' ')
  FROM MY_TABLE
      ,LATERAL FLATTEN(MY_TABLE.MY_DICT:"list") F1
      ,LATERAL FLATTEN(F1.VALUE:"element":"value":"list") F2
;

EDIT (based on your comment about wanting rows, not a concatenated string column):

Simply remove the LISTAGG(), as follows:

SELECT F1.VALUE:"element":"type"::VARCHAR || ', ' || F2.VALUE:"element"::VARCHAR AS TYPE_ELEMENT
  FROM MY_TABLE
      ,LATERAL FLATTEN(MY_TABLE.MY_DICT:"list") F1
      ,LATERAL FLATTEN(F1.VALUE:"element":"value":"list") F2
;

If you want a simple result set, with 2 columns (unclear from your specification), then you can just use this:

SELECT F1.VALUE:"element":"type"::VARCHAR AS TYPE
      ,F2.VALUE:"element"::VARCHAR AS ELEMENT
  FROM MY_TABLE
      ,LATERAL FLATTEN(MY_TABLE.MY_DICT:"list") F1
      ,LATERAL FLATTEN(F1.VALUE:"element":"value":"list") F2
;



回答4:


select
    id,
    f1.value:element:type::string type,
    f2.value:element::string element
from
    table,
    lateral flatten(input => table.json, path => 'list') f1,
    lateral flatten(input => f1.value:element:value:list) f2


来源:https://stackoverflow.com/questions/63920653/flatten-nested-json-in-snowflake

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!