问题
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