Permanently changing column name in JSON SNOWFLAKE - snowflake-cloud-data-platform

2 { "country": "England", "id": "100200", "status": "morestatus" }
3 { "country": "Netherlands", "id": "100300", "status": "morestatus" }
1 { "country": "UK", "id": "100100", "status": "somestatus" }
how to change the country to COUNTRY permanently with update command:
SET T.RECORD = object_delete(object_insert(RECORD, 'COUNTRY', RECORD:country), 'country')
WHERE T.RECORD:country

You can nest object_insert inside object_delete to do this.
create or replace temp table t1 as select parse_json('{ "country": "England", "id": "100200", "status": "morestatus" }') as V;
insert into t1 select parse_json('{ "country": "Netherlands", "id": "100300", "status": "morestatus" }');
insert into t1 select parse_json('{ "country": "UK", "id": "100100", "status": "somestatus" }');
update t1 set v = object_delete(object_insert(v, 'COUNTRY', v:country), 'country');

Related

How to get values from object as an array

We need to convert the object to an Array of objects and do map on the field but the field is incremental like field1, field2 which is where we got stuck.
I tried the below code:
output application/json
---
payload.main.field map(value) -> {
"name": value.name,
"age": value.age,
"location": value.location[0].country
}
Input:
{
"main": {
"field1": {
"name": "value",
"age": 20,
"address": {
"location": [
{
"country": "US",
"zipcode": 1234
},
{
"country": "US",
"zipcode": 1234
}
]
}
},
"field2": {
"name": "pqr",
"age": 23,
"address": {
"location": [
{
"country": "CA",
"zipcode": 1235
},
{
"country": "US",
"zipcode": 1234
}
]
}
},
"field3": {
"name": "abc",
"age": 22,
"address": {
"location": [
{
"country": "BU",
"zipcode": 1236
},
{
"country": "US",
"zipcode": 1234
}
]
}
}
}
}
For the above Input, Below is the expected response.
Expected Output:
{
"main": [
{
"name": "value",
"age": 20
"location": "US"
},
{
"name": "pqr",
"age": 23
"location": "CA"
},
{
"name": "abc",
"age": 22
"location": "BU"
}
]
}
For location, it will be like location[0].country when the array size is not 0 and country not null.
output application/json
---
main : payload.main pluck $ map {
"name": $.name,
"age": $.age,
"location": if( sizeOf($.address.location) !=0) $.address.location[0].country else "N/A"
}

Retrieve JSON Nested Values Via OPENJSON

Need to retrieve the values of Batters/Batter/Type 1-4
Here is the JSON data
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
Used selected * from openjson to retrieve the values, but unable to get the nested/nested values
Select * from openjson(#json_known, '$[1]')
with
(
KeyID int '$.id',
[Type] varchar(max) '$.type',
[Name] varchar(max) '$.name',
PPU varchar(max) '$.ppu',
Batter0 varchar(max) '$.batters.batter.type[0]',
Batter1 varchar(max) '$.batters.batter.id[1]',
Batter2 varchar(max) '$.batters.batter.type[2]',
Batter3 varchar(max) '$.batters.batter.type[3]'
)
You could use:
Select x.Batter
from openjson(#json_known, '$') s
cross apply openjson(json_query(s.value, '$.batters.batter'))
with (id INT '$.id',Batter varchar(max) '$.type') x;
db<>fidlde demo

Merge array of hash with same key

I have an array of hash as shown here. I want to merge the values of some fields with custom seprators. Here, i show only two hashes in the array, it is possible to have more. But, they are always in same sequence as shown here.
{
"details": [
{
"place": "abc",
"group": 3,
"year": 2006,
"id": 1304,
"street": "xyz 14",
"lf_number": "0118",
"code": 4433,
"name": "abc coorperation",
"group2": 3817,
"group1": 32,
"postal_code": "22926",
"status": 2
},
{
"place": "cbc",
"group": 2,
"year": 2007,
"id": 4983,
"street": "mnc 14",
"lf_number": "0145",
"code": 4433,
"name": "abc coorperation",
"group2": 3817,
"group1": 32,
"postalcode": "22926",
"status": 2
}
],
"#timestamp": "2017-09-04",
"parent": {
"child": [
{
"w_2": 0.5,
"w_1": 0.1,
"id": 14226,
"name": "air"
},
{
"w_2": null,
"w_1": 91,
"id": 25002,
"name": "Water"
}]
},
"p_name": "anacin",
"#version": "1",
"id": 28841
}
I want to edit the details. I want to construct new fields.
Field 1) coorperations: (details.name | details.postal_code details.street ; details.name | details.postal_code details.street)
Output:
Coorperations: (abc coorperation |22926 xyz 14; abc coorperation | 22926 mnc 14)
Field 2) access_code: (details.status-details.id-details.group1-details.group2-details.group(always two digit)/details.year(only last two digits); details.status-details.id-details.group1-details.group2-details.group(always two digit)/details.year(only last two digits))
Output: access_code (2-32-3817-03-06; 2-32-3817-02-07)
How can I achieve this for all the values in details. Here is how final results should look like.
{
"#timestamp": "2017-09-04",
"parent": {
"child": [
{
"w_2": 0.5,
"w_1": 0.1,
"id": 14226,
"name": "air"
},
{
"w_2": null,
"w_1": 91,
"id": 25002,
"name": "Water"
}]
},
"p_name": "anacin",
"#version": "1",
"id": 28841,
"Coorperations" : "abc coorperation |22926 xyz 14; abc coorperation | 22926 mnc 14",
"access_code" : "2-32-3817-03-06; 2-32-3817-02-07"
}
You can try to run this code in rails console with hash is your json:
new_hash = hash.except(:details)
coorperations = ""
access_code = ""
elements = hash[:details]
elements.each do |element|
coorperations = "#{coorperations}#{if coorperations.present? then '; ' else '' end}#{element[:name]} | #{element[:postal_code]} #{element[:street]}"
access_code = "#{access_code}#{if access_code.present? then '; ' else '' end}#{element[:status]}-#{element[:id]}-#{element[:group1]}-#{element[:group2]}-#{element[:group1]}-#{element[:group]}"
end
new_hash.merge!(Coorperations: coorperations)
new_hash.merge!(access_code: access_code)
new_hash

Postgres queries for JSON Array

I have a table called cust_data which stores id and JSON object. I want to write postgres select statements to fetch:
select all id's where "gender": "Female" is not present in persons array [this should return id#3 from below data]
select all id's where "gender": "Female" is present and "status":"married" [this should return id#2 from below data]
Table : cust_data
id(numeric) | connections (jsonb)
------------------------------
1, {"Persons": [
{
"personName": "Tom",
"gender": "Male",
"country": "USA",
"status":"single"
},
{
"personName": "Harry",
"gender": "Male",
"country": "USA",
"status":"single"
},
{
"personName": "Lisa",
"gender": "Female",
"country": "Mexico",
"status":"single"
}
]
}
2,{
"Persons": [
{
"personName": "Lisa",
"gender": "Male",
"country": "UK",
"status":"single"
},
{
"personName": "Harry",
"gender": "Male",
"country": "USA",
"status":"single"
},
{
"personName": "Lisa",
"gender": "Female",
"country": "Mexico",
"status":"married"
}
]
}
3,{
"Persons": [
{
"personName": "Lisa",
"gender": "Male",
"country": "UK",
"status":"single"
},
{
"personName": "Harry",
"gender": "Male",
"country": "USA",
"status":"single"
}
]
}
You can use boolean aggregate functions:
select id
from cust_data,
lateral jsonb_array_elements(connections->'Persons')
group by 1
having not bool_or(value->>'gender' = 'Female');
id
----
3
(1 row)
select id
from cust_data,
lateral jsonb_array_elements(connections->'Persons')
group by 1
having bool_or(value->>'gender' = 'Female' and value->>'status' = 'married');
id
----
2
(1 row)
Test it here.
If the arrays may be empty you should use left join ... on true instead of lateral. Add also coalesce() with appropriate default value for aggregates as they can yield null, e.g.:
select id
from cust_data
left join jsonb_array_elements(connections->'Persons') on true
group by 1
having not coalesce(bool_or(value->>'gender' = 'Female'), false);
Query for 1:
WITH test AS (
SELECT id, jsonb_array_elements(t.connections->'Persons') AS elem
FROM cust_data t
), findFemale AS (
SELECT DISTINCT id FROM test
WHERE elem->>'gender' = 'Female'
)
SELECT id FROM cust_data
WHERE id NOT IN (select * from findFemale)
Query for 2:
WITH test as (SELECT id, jsonb_array_elements(t.connections->'Persons') AS elem
from cust_data t
) , findFemaleMarried as (
select distinct id from test
where
elem ->> 'gender' = 'Female' and elem ->> 'status' = 'married'
)
select * from findFemaleMarried
I hope above query will solve your problem.

Need help in fetching specific Objects from JSON array

I have a JSON array in the following format, and I need to fetch the objects that belong to the same country i.e having the same value for the "country" key or "country_short" key in my JSP. Could any one please help?
[{
"country_short": "USA",
"city": "Butler",
"description": "",
"date_new": "2016-09-27 21:26:23",
"url": "--",
"country": "United States",
"company": "Cargill",
"title": "Yard Driver",
"reqid": "BUT00451",
"state": "Wisconsin",
"state_short": "WI",
"location": "Butler, WI",
"guid": "04F2182583FC429BBAEF8B86F8467A55",
"uid": null
}, {
"country_short": "CAN",
"city": "Camrose",
"description": "",
"date_new": "2016-09-27 21:26:23",
"url": "--",
"country": "Canada",
"company": "Cargill",
"title": "Agronomy Associate",
"reqid": "CAN00437",
"state": "Alberta",
"state_short": "AB",
"location": "Camrose, AB",
"guid": "9FB7383A512F48F893C535765F9FBE4F",
"uid": null
}]
Thanks in Advance!
You can use the JS filter method like this
a.filter(function(item){ return item.country_short.toLowerCase() == 'usa'});

Resources