I have nested struct data in DB I need to migrate that to snowflake how can I replicate that nested struct in snowflake. In snowflake I don't have struct data type it is only variant.
so google finds:
https://gist.github.com/irajhedayati/c595e349d68b7a5074da81f1b8c6eec5
which has some code like:
INSERT into calls_nested
SELECT
'5' AS call_id,
'Jack' AS name,
45 AS age,
named_struct('first_name', 'Joe', 'last_name', 'Doe') AS account,
named_struct('home', '514-111-2222', 'work', '514-333-4444') AS phone_directory,
array(
named_struct('street', '1 Guy', 'city', 'Montreal'),
named_struct('street', '1 McGill', 'city', 'Montreal')
) AS addresses;
named_struct -> object_construct
array -> array_construct
and you just keep stacking them if that's what you want.
SELECT
'5' AS call_id,
'Jack' AS name,
45 AS age,
object_construct('first_name', 'Joe', 'last_name', 'Doe') AS account,
object_construct('home', '514-111-2222', 'work', '514-333-4444') AS phone_directory,
array_construct(
object_construct('street', '1 Guy', 'city', 'Montreal'),
object_construct('street', '1 McGill', 'city', 'Montreal')
) AS addresses,
object_construct('call_id', call_id, 'name', name, 'age' ,age, 'account', account, 'phone_directory', phone_directory, 'addresses',addresses) as object_of_objects
;
CALL_ID
NAME
AGE
ACCOUNT
PHONE_DIRECTORY
ADDRESSES
OBJECT_OF_OBJECTS
5
Jack
45
{ "first_name": "Joe", "last_name": "Doe" }
{ "home": "514-111-2222", "work": "514-333-4444" }
[ { "city": "Montreal", "street": "1 Guy" }, { "city": "Montreal", "street": "1 McGill" } ]
{ "account": { "first_name": "Joe", "last_name": "Doe" }, "addresses": [ { "city": "Montreal", "street": "1 Guy" }, { "city": "Montreal", "street": "1 McGill" } ], "age": 45, "call_id": "5", "name": "Jack", "phone_directory": { "home": "514-111-2222", "work": "514-333-4444" } }
Related
CREATE TABLE Log (
"Name" TEXT,
"Age" TEXT,
"Country" TEXT,
"Numbers" TEXT
);
SELECT "Country", "Numbers"
FROM json_populate_record( null:: log,
'{
"Name": "qazwsx",
"HostName": "Age",
"Address": {
"Country": "MNB",
"Numbers": [
{
"Cell": 7418520
}
]
}
}');
SELECT * FROM Log
DEMO: The response is always null. Is there any other trick to insert nested JSON into the table?
CREATE TABLE Log (
"Name" TEXT,
"Age" TEXT,
"Country" TEXT,
"Numbers" TEXT
);
INSERT INTO Log VALUES('Oslo', '12', 'No', '12');
SELECT jsonb_pretty(
json_build_object(
'Name',
'qazwsx',
'HostName',
"Age",
'Address',
json_build_object(
'Country',
'MNB',
'Numbers',
json_build_object('Cell',7418520)
)
)::jsonb
) AS Output
FROM Log;
Output:
{
"Name": "qazwsx",
"HostName": "12",
"Address": {
"Country": "MNB",
"Numbers": {
"Cell": 7418520
}
}
}
A quick and dirty example:
SELECT
json_extract_path_text('{"Name": "qazwsx","HostName": "Age","Address": {
"Country": "MNB", "Numbers": [{"Cell":7418520}]}}'::json, 'Address', 'Country') AS "Country",
json_extract_path_text('{"Name": "qazwsx","HostName": "Age","Address": {
"Country": "MNB", "Numbers": [{"Cell":7418520}]}}'::json, 'Address', 'Numbers') AS "Numbers";
Country | Numbers
---------+--------------------
"MNB" | [{"Cell":7418520}]
A little better version using the JSON path language from her JSON functions9.16.2. The SQL/JSON Path Language:
SELECT
t[0] AS "Country",
t[1] AS "Numbers"
FROM
jsonb_path_query_array('{"Name": "qazwsx","HostName": "Age","Address": {
"Country": "MNB", "Numbers": [{"Cell":7418520}]}}'::jsonb, '$.Address.*') AS t;
Country | Numbers
---------+---------------------
"MNB" | [{"Cell": 7418520}]
Though the above does depend on the ordering in the Address object staying the same.
CREATE TABLE Log (
"Name" TEXT,
"Age" TEXT,
"Country" TEXT,
"Numbers" TEXT
);
DECLARE
jsonstr text;
jsonobj jsonb;
jsonstr = '{
"Name": "qazwsx",
"HostName": "Age",
"Address": {
"Country": "MNB",
"Numbers": [
{
"Cell": 7418520
}
]
}
}';
SELECT jsonstr::json INTO jsonobj;
INSERT INTO
Log
SELECT
jsonobj->'Name',
jsonobj->'HostName'
((jsonobj->'Address')::json)->'Country',
(((jsonobj->'Address')::json)#>'{Numbers,0}')::json->'Cell';
SELECT * FROM Log
I have sample data in a SQL Server table in the following format
CREATE TABLE #tempA
(
HomeId int IDENTITY PRIMARY KEY,
City nvarchar(20),
State nchar(2),
Email VARCHAR(50)
);
INSERT INTO #tempA (City, State, Email)
VALUES ('Cleveland', 'OH', 'sd#aol.com')
INSERT INTO #tempA (City, State, Email)
VALUES ('Malibu', 'CA', 'sd#aol.com')
INSERT INTO #tempA (City, State, Email)
VALUES ('Atlanta', 'GA', 'ploll#aol.com')
SELECT * FROM #tempA
I need a JSON output returned by a stored procedure in the following format, I am trying to group it by email field, I tried using JSON AUTO but not able to achieve in the following format ? Any tips?
[
{
"Email": "sd#aol.com",
"Tasks": [
{
"City": "Cleveland",
"State": "OH"
},
{
"City": "Malibu",
"State": "CA"
}
]
},
{
"Email": "ploll#aol.com",
"Tasks": [
{
"City": "Atlanta",
"State": "GA"
}
]
}
]
One method would be to use a subquery for the State and Email values and group on the email column in the outer query:
SELECT A.Email,
(SELECT B.City,
B.State
FROM #tempA B
WHERE A.Email = B.Email
ORDER BY B.City ASC
FOR JSON AUTO) AS Tasks
FROM #tempA A
GROUP BY A.Email
ORDER BY A.Email DESC
FOR JSON AUTO;
Which gives:
[
{
"Email": "sd#aol.com",
"Tasks": [
{
"City": "Cleveland",
"State": "OH"
},
{
"City": "Malibu",
"State": "CA"
}
]
},
{
"Email": "ploll#aol.com",
"Tasks": [
{
"City": "Atlanta",
"State": "GA"
}
]
}
]
I have a Json like this in my JsonB column:
{
"emails": [
{
"email": {
"id": "a8399412-165e-4601-824f-a55f631ad471",
"value": "test#gmail.com"
}
},
{
"email": {
"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e",
"value": "test1#gmail.com"
}
}
],
"Address": [
{
"address": {
"id": "a8399412-165e-4601-824f-a55f631ad471",
"addressLine1": "Line1"
}
},
{
"address": {
"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e",
"addressLine2": "Line2"
}
}
],
"lastName": {
"id": "bc10a5a9-04ff-4a00-b167-ac3232e5cb89",
"value": "LastName"
},
"firstName": {
"id": "4ccdd400-2586-4a7f-9379-aff4d1f5d9d6",
"value": "FirstName"
}
}
and so on. My requirement to get list of elements as key and value pairs with limit, I did a research tried different functions of postgres and I wrote the below query :
select response.* from my_table t, jsonb_each_text(jsonb_column) as response;
If I do like this I'm getting only the root elements like emails, firstName and lastName, but I want inner elements as well along with their values like below :
Key | value
------- ---------
"email" : {"id": "a8399412-165e-4601-824f-a55f631ad471","value": "test#gmail.com"}
"email" : {"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e","value": "test1#gmail.com"}
"lastName" : {"id": "bc10a5a9-04ff-4a00-b167-ac3232e5cb89","value": "LastName"}
"firstName" : {"id": "4ccdd400-2586-4a7f-9379-aff4d1f5d9d6","value": "FirstName"}
"address" : {"id": "a8399412-165e-4601-824f-a55f631ad471", "addressLine1": "Line1"}
"address" : {"id": "a8399412-165e-4601-824f-a55f631ad471", "addressLine2": "Line2"}
You can use jsonb_array_elements() function, and combine queries by UNION ALL
SELECT 'email' AS key, je.* ->> 'email' AS value
FROM my_table
CROSS JOIN jsonb_array_elements(jsonb_column->'emails') AS je
UNION ALL
SELECT 'address', ja.* ->> 'address'
FROM my_table
CROSS JOIN jsonb_array_elements(jsonb_column->'Address') AS ja
UNION ALL
SELECT 'lastName', (jsonb_column->'lastName')::text
FROM my_table
UNION ALL
SELECT 'firstName', (jsonb_column->'firstName' )::text
FROM my_table
Demo
I am trying to remove the "attribute" from the output of Azure SQL for json path.
Consider the below test data:
create table test (country varchar(50), city varchar(50));
insert into test values ('US', 'New York');
insert into test values ('US', 'Las Vegas');
insert into test values ('France', 'Paris');
insert into test values ('Canada', 'Toranto');
insert into test values ('Canada', 'Vancouver');
The below SQL when run gives the output shown:
select DISTINCT country, (select city
from test b
where b.country=a.country
for json path
) as city
from test a
for json path;
Output:
[
{
"country": "Canada",
"city": [
{
"city": "Toranto"
},
{
"city": "Vancouver"
}
]
},
{
"country": "France",
"city": [
{
"city": "Paris"
}
]
},
{
"country": "US",
"city": [
{
"city": "New York"
},
{
"city": "Las Vegas"
}
]
}
]
However, I would like the output to be of the below form i.e. city attribute removed from the output and the values as an array
[
{
"country": "Canada",
"city": [
"Toranto"
, "Vancouver"
]
},
{
"country": "France",
"city": [
"Paris"
]
},
{
"country": "US",
"city": [
"New York"
,"Las Vegas"
]
}
]
Thanks
Check if the following works for you:
select DISTINCT country as country,json_query((select CONCAT('[','"', STRING_AGG(city, '","'), '"',']')
from test b
where b.country=a.country
)) as city
from test a
for json path
Example here.
I have a struct which looks like this:
{"event": {
"timestamp": [
"2019-01-13 17:21:08.570140 UTC",
"2019-01-14 14:10:55.475515 UTC",
"2019-01-09 14:02:51.848917 UTC"
],
"properties": [
{"device_model": "iPhone", "country": "United Kingdom"},
{"device_model": "Android", "country": "United States"},
{"device_model": "iPhone", "country": "Sweden"}
]
}
I would like to achieve this: so that each timestamp enters corresponding struct.
{"event": [
{"timestamp": "2019-01-13 17:21:08.570140 UTC","device_model":
"iPhone", "country": "United Kingdom"},
{"timestamp": "2019-01-14 14:10:55.475515 UTC", "device_model":
"Android", "country": "United States"},
{"timestamp": "2019-01-09 14:02:51.848917 UTC", "device_model":
"iPhone", "country": "Sweden"}
]
}
I created the current structure from a query like this:
WITH
events AS (
SELECT
"customer_1" AS customer_id,
"timestamp_1" AS timestamp,
STRUCT("iphone" AS device_model,
"uk" AS country ) AS properties
UNION ALL
SELECT
"customer_2" AS customer_id,
"timestamp_2" AS timestamp,
STRUCT("android" AS device_model,
"us" AS country) AS properties
UNION ALL
SELECT
"customer_2" AS customer_id,
"timestamp_3" AS timestamp,
STRUCT("iphone" AS device_model,
"sweden" AS country) AS properties )
SELECT
customer_id,
STRUCT(ARRAY_AGG(timestamp) AS timestamp,
ARRAY_AGG(properties) AS properties) AS event
FROM
events
GROUP BY
customer_id
How can I modify the query to achieve the desired structure?
--- Edit
I could do it this way, but this requires knowing the schema of properties at the time when I am generating query - which is possible, but not very pretty. Is there a simpler way?
WITH
events AS (
SELECT
"customer_1" AS customer_id,
"timestamp_1" AS timestamp,
STRUCT("iphone" AS device_model,
"uk" AS country ) AS properties
UNION ALL
SELECT
"customer_2" AS customer_id,
"timestamp_2" AS timestamp,
STRUCT("android" AS device_model,
"us" AS country) AS properties
UNION ALL
SELECT
"customer_2" AS customer_id,
"timestamp_3" AS timestamp,
STRUCT("iphone" AS device_model,
"sweden" AS country) AS properties )
SELECT
customer_id,
ARRAY_AGG(properties) AS event
FROM (
SELECT
customer_id,
struct(timestamp as timestamp,
properties.device_model as device_model,
properties.country as country) as properties
FROM
events)
GROUP BY
customer_id
You could do something like this leveraging SELECT AS STRUCT and using properties as a selector.
SELECT
customer_id,
ARRAY_AGG(properties) AS prop
FROM (
SELECT
customer_id,
(
SELECT
AS STRUCT timestamp,
properties.*) AS properties
FROM
events e )
GROUP BY
1
this returns:
[
{
"customer_id": "customer_1",
"prop": [
{
"timestamp": "timestamp_1",
"device_model": "iphone",
"country": "uk"
}
]
},
{
"customer_id": "customer_2",
"prop": [
{
"timestamp": "timestamp_2",
"device_model": "android",
"country": "us"
},
{
"timestamp": "timestamp_3",
"device_model": "iphone",
"country": "sweden"
}
]
}
]
You could further write the piece like:
SELECT AS STRUCT e.* except(customer_id)