dynamically flatten json using snowflake function - snowflake-cloud-data-platform

Is it possible to dynamically flatten json using snowflake function ?
select key,value from table a ,lateral flatten(input => variant_column)
gives
which need to be converted as

I've assumed your source JSON is something like this:
[
{
"empname": "e1",
"empid": 123
},
{
"empname": "e2",
"empid": 456
}
]
Based on this, you can achieve the output you want using:
select
s.value:empname::varchar as empname,
s.value:empid::number as empid
from
json j,
lateral flatten (input => j.src, path => '', mode => 'ARRAY') s
;
Full example replication code:
create or replace table json (src variant);
insert into json(src) select parse_json($$
[
{
"empname": "e1",
"empid": 123
},
{
"empname": "e2",
"empid": 456
}
]
$$
);
select * from json;
select
s.value:empname::varchar as empname,
s.value:empid::number as empid
from
json j,
lateral flatten (input => j.src, path => '', mode => 'ARRAY') s
;

Related

Insert key-value into ALL objects of the JSON array

I have JSON array value column in database:
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
}
]
I want to add a new key-value into each object. Expected result is:
[
{
"id": 1,
"name": "One",
"active": "1"
},
{
"id": 2,
"name": "Two",
"active": "1"
}
]
By using JSON_MODIFY I can add a new key-value into one of the object as following:
UPDATE MyTable
SET JsonValueColumn=JSON_MODIFY(JsonValueColumn,'$[1].active','1')
WHERE Id = 'id'
But I need to add a new key-value into all objects in JSON array. I have an option to iterate in json objects, add new key-value, combine them again and update JsonValueColumn with the new value.
But I am looking if there is a simpler way to achieve this. Something like:
UPDATE MyTable
SET JsonValueColumn=JSON_MODIFY(JsonValueColumn,'$[*].active','1')
WHERE Id = 'id'
This is the simplest way I found so far:
UPDATE MyTable
SET JsonValueColumn= '[' + (
SELECT
STRING_AGG(JSON_MODIFY([value],'$.active', '1'), ',') WITHIN GROUP (ORDER BY CAST([key] AS int))
FROM
OPENJSON(JsonValueColumn)
) + ']'
From: https://stackoverflow.com/a/62648430/2794280
You can use OPENJSON to break out the JSON objects, then CROSS APPLY the new value, then rebuild with FOR JSON:
UPDATE MyTable
SET JsonValueColumn =
(SELECT *
FROM OPENJSON(#json) WITH (id int, name varchar(100))
CROSS APPLY (VALUES(1)) v(active)
FOR JSON PATH);

SNOWFLAKE querying the array of elements

I am using SNOW_FLAKE and trying to query the data stored in the form of array of elements under column name nested_colmn as example:
nested_colmn
[
{
"firstKey": "val1",
"secondKey": 2555,
"thirdKey": false,
"fourthkey": "otrvalue"
},
{
"firstKey": "val2",
"secondKey": 255221,
"thirdKey": true,
"fourthkey": "otrvalu"
}
]
The above Array gets returned as one complete row if I do
Select nested_colmn from table_name
Now I want to query/get the results only for the firstkey(nested_colmn.firstkey) from the Attributes column. How do I frame the query to be to retrieve the individual custom elements from an array instead of getting all. Please help me if any thoughts on this
Note: I will assume that you truly want the source table to have the array as a value, instead of stripping the outer array and placing each element into its own row.
First, create a test table with your sample data:
CREATE OR REPLACE TEMPORARY TABLE table_name (
nested_colmn VARIANT
)
AS
SELECT PARSE_JSON($1) AS nested_colmn
FROM VALUES
($$
[
{
"firstKey": "val1",
"secondKey": 2555,
"thirdKey": false,
"fourthkey": "otrvalue"
},
{
"firstKey": "val2",
"secondKey": 255221,
"thirdKey": true,
"fourthkey": "otrvalu"
}
]
$$)
;
With that, here is a sample query:
SELECT F.VALUE:"firstKey"::VARCHAR AS FIRST_KEY
FROM table_name T
,LATERAL FLATTEN(nested_colmn) F
;
You're going to need to run a lateral flatten on the array and then parse the JSON:
WITH x as (
SELECT array_construct(parse_json('
{
"firstKey": "val1",
"secondKey": 2555,
"thirdKey": false,
"fourthkey": "otrvalue"
}'),parse_json('
{
"firstKey": "val2",
"secondKey": 255221,
"thirdKey": true,
"fourthkey": "otrvalu"
}')) as var)
SELECT p.value:firstKey::varchar
FROM x,
lateral flatten(input => x.var) p;

Snowflake query for retrieving JSONs that contain string in ANY element of a list

The JSON object contains this:
"entities": {
"hashtags": [
{
"indices": [
17,
29
],
"text": "HBOMAX4ZACK"
},
{
"indices": [
38,
51
],
"text": "TheSnyderCut"
}
],
I want to select only those rows that contain 'XYZ' in ANY ONE of the entries in 'hashtags'. I know I can do this:
select record_content:text, * from tweets where record_content:entities:hashtags[0].text = 'HBOMAX4ZACK';
But as you can see, I have hard-coded 'hashtags[0]' in this case. I want to check if 'HBOMAX4ZACK' exists in any element.
Use lateral and FLATTEN to explode the json. With flatten you are exploding the json up to the level you need (in path):
select t.json,
t2.VALUE value_matching
from (select parse_json('{
"entities": {
"hashtags": [{
"indices": [
17,
29
],
"text": "HBOMAX4ZACK"
},
{
"indices": [
38,
51
],
"text": "TheSnyderCut"
}
]
}
}') as json) t,
lateral flatten(input => parse_json(t.json), path => 'entities.hashtags') t2
WHERE t2.VALUE:text = 'HBOMAX4ZACK';
You can find a tutorial to the topic here https://community.snowflake.com/s/article/How-To-Lateral-Join-Tutorial

ambiguous column name 'VALUE'

Any idea to overcome ambiguous column with snowflake lateral flatten function error with below logic is much appreciated.
I'm trying to flatten the nested JSON data using the below query by selecting the value from variant column, However getting ambiguous column name 'VALUE' error with lateral flatten function. Can someone help me to achieve the desired output. Issue here is the JSON key name is coming as "value" and I couldn't get that data using lateral flatten. Desired output has been attached as image to this thread.
Sample JSON Data
{"issues": [
{
"expand": "a,b,c,d",
"fields": {
"customfield_10000": null,
"customfield_10001": null,
"customfield_10002": [
{
"id": "1234",
"self": "xxx",
"value": "Test"
}
],
},
"id": "123456",
"key": "K-123"
}
]}*
*select
a.value:id::number as ISSUE_ID,
a.value:key::varchar as ISSUE_KEY,
b.value:id::varchar as ROOT_CAUSE_ID,
**b.value:value::varchar as ROOT_CAUSE_VALUE**
from
abc.table_variant,
lateral flatten( input => payload_json:issues) as a,
lateral flatten( input => a.value:fields.customfield_10002) as b;*
Try
b.value:"value"::varchar
WITH CTE AS
(select parse_json('{"issues": [
{
"expand": "a,b,c,d",
"fields": {
"customfield_10000": null,
"customfield_10001": null,
"customfield_10002": [
{
"id": "1234",
"self": "xxx",
"value": "Test"
}
],
},
"id": "123456",
"key": "K-123"
}
]}')
as col)
select
a.value:id::number as ID,
a.value:key::varchar as KEY,
b.value:id::INT as customfield_10002,
b.value:value::varchar as customfield_10002_value
from cte,
lateral flatten(input => cte.col, path => 'issues') a,
lateral flatten(input => a.value:fields.customfield_10002) b;

Nest Json Array merge

I have a column saved json data in my table:
declare #json nvarchar(max)
set #json = N'
{
"Companies": [
{
"CompanyId": "A",
"Employee": null
},
{
"CompanyId": "B",
"Employee": [
{
"EmployeePictureId": null,
"Name": "Employee1"
},
{
"EmployeePictureId": "PictureId2",
"Name": "Employee2"
}
]
},
{
"CompanyId": "C",
"Employee": [
{
"EmployeePictureId": null,
"Name": "Employee3"
},
{
"EmployeePictureId": null,
"Name": "Employee4"
}
]
}
]
}
'
Is it posible to get the result like:
{
"EmployeePictureIds": ["PictureId2"]
}
using the Json_Query, Json_Value, OPENJSON...
Only get EmployeePictureId and skip empty(null) data
By the way, the count of elements in array are not sure.
In SQL Server 2017 you can use the following query:
select json_query(QUOTENAME(STRING_AGG('"' + STRING_ESCAPE( A.EmployeePictureId , 'json')
+ '"', char(44)))) as [EmployeePictureIds]
FROM OPENJSON(#json, '$.Companies')
WITH
(
CompanyId NVARCHAR(MAX),
Employee NVARCHAR(MAX) as json
) as B
cross apply openjson (B.Employee)
with
(
EmployeePictureId VARCHAR(50),
[Name] VARCHAR(50)
) as A
where A.EmployeePictureId is not null
for json path , WITHOUT_ARRAY_WRAPPER
Results for the JSON you provided:
Results adding another non null EmployeePictureId:

Resources