How to parse this json in snowflake - snowflake-cloud-data-platform

{
"segmentId": "b204c220-ea8d-4cf4-b579-30eb59a1a2a4",
"diffFields": [
{
"fieldName": "name",
"valueBefore": null,
"valueAfter": "new-segment-name"
},
{
"fieldName": "active",
"valueBefore": null,
"valueAfter": true
}
]
}
In the above json I have an array of diffFields . I am trying to parse this in snowflake get the array of columns instead of rows.
I tried flatten, but this flatten it as rows.
I am trying to parse this in dbt to create another table from the above json with table structure as
create table some_table (
field_one,
--if `name` is present in the above json I want that to be 2nd column
-- if `active` is present in the above json i want that to be 3nd column
)
)

I would flatten it like
WITH data as (
select parse_json('
{
"segmentId": "b204c220-ea8d-4cf4-b579-30eb59a1a2a4",
"diffFields": [
{
"fieldName": "name",
"valueBefore": null,
"valueAfter": "new-segment-name"
},
{
"fieldName": "active",
"valueBefore": null,
"valueAfter": true
}
]
}') as json
)
select
json:segmentId::text as seg_id,
f.value:fieldName::text as fieldName,
f.value:valueBefore as valueBefore,
f.value:valueAfter as valueAfter
from data, table(flatten(input=>json:diffFields)) f
which gives:
SEG_ID
FIELDNAME
VALUEBEFORE
VALUEAFTER
b204c220-ea8d-4cf4-b579-30eb59a1a2a4
name
null
"new-segment-name"
b204c220-ea8d-4cf4-b579-30eb59a1a2a4
active
null
true
but those variant data nulls are not real nulls. so you want to use something like is_null_value to test and covert to real nulls
To select array parts:
select json:segmentId::text
,max(iff(f.value:fieldName::text = 'name', f.value, null)) as name_object
,max(iff(f.value:fieldName::text = 'active', f.value, null)) as active_object
from data, table(flatten(input=>json:diffFields)) f
group by 1;
gives:
JSON:SEGMENTID::TEXT
NAME_OBJECT
ACTIVE_OBJECT
b204c220-ea8d-4cf4-b579-30eb59a1a2a4
{ "fieldName": "name", "valueAfter": "new-segment-name", "valueBefore": null }
{ "fieldName": "active", "valueAfter": true, "valueBefore": null }

You can use QuickTable to connect snowflake and do JSON parse use QuickTable. QuickTable can generate related SQL that is compatible with Snowflake.

Related

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;

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;

How do I extract values from a jsonb array of objects?

I am using Postgres and I am trying to get all the elements in the array that's has a keys statusCode and place the values into an array so I can display it.
"systemStatuses": [
{
"changedBy": "monsjenni557",
"timeStamp": 1554151540.9612856,
"statusCode": "S01",
"statusDescription": "Received"
},
{
"changedBy": "monsjenni557",
"timeStamp": 1554151546.2600567,
"statusCode": "SF02",
"statusDescription": "Request Validation Fail"
}
]
the result should be ["S01","SF02"]
You can expand and then aggregate back the jsonb field. The WITH section is only here for example purposes.
WITH exampleData AS (
SELECT '[
{
"changedBy": "monsjenni557",
"timeStamp": 1554151540.9612856,
"statusCode": "S01",
"statusDescription": "Received"
},
{
"changedBy": "monsjenni557",
"timeStamp": 1554151546.2600567,
"statusCode": "SF02",
"statusDescription": "Request Validation Fail"
}
]'::jsonb as regionSales
)
SELECT (
SELECT jsonb_agg( sale -> 'statusCode')
FROM jsonb_array_elements(regionSales) AS sale
)
FROM exampleData

Querying for an array object in Postgres jsonb column

I have a Postgres table with 2 columns "nodes" & "timestamp".The "nodes" column is of type jsonb & is an array of objects of the following format:
[
{
"addr": {},
"node_number": "1",
"primary": false
},
{
"addr": {},
"node_number": "2",
"primary": true
},
]
I want to find the object in this array that has "primary":true in the most recent row. If the above was the latest row, the result should be:
{
"addr": { },
"node_number": "2",
"primary": true
}
I have tried:
SELECT(nodes -> 0) FROM table WHERE nodes #> '[{"primary": true}]'
order by timestamp desc
limit 1;
which gives the object at index 0 in the array not the desired object that has "primary": true.
How can I implement the query ?
Use jsonb_array_elements() in a lateral join:
select elem
from my_table
cross join jsonb_array_elements(nodes) as elem
where (elem->>'primary')::boolean
elem
---------------------------------------------------
{"addr": {}, "primary": true, "node_number": "2"}
(1 row)

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