Extract with JSON_QUERY - json

The JSON string we have stored in the table has this format to it:
[
{
"itemid" : "18726539",
"duration" : "19:28",
"title" : "Flight Plan for Trading: Market Lessons from My Pilot Dad",
"description" : "<p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>",
"pubDate" : "Wed, 14 Apr 2021 18:04:19 +0000"
}
]
When I test it with IS JSON, all the data comes back. So, Oracle is seeing this as JSON. However, I'm not sure how to get the "itemid" and "description" items. I tried this query, but it comes up empty:
SELECT JSON_QUERY(json_str, '$.itemid' RETURNING VARCHAR2(30) WITH ARRAY WRAPPER) AS overview FROM json_podcast_data;
I'm thinking that the leading bracket might be causing an issue?
Any help is greatly appreciated.

Rather than using multiple JSON_VALUE functions, you can use a single JSON_TABLE:
SELECT j.itemid,
j.duration,
j.title,
j.description,
TO_TIMESTAMP_TZ(
j.pubdate,
'Dy, DD Mon YYYY HH24:MI:SS TZHTZM',
'NLS_DATE_LANGUAGE=American'
) AS pubdate
FROM json_podcast_data d
CROSS JOIN JSON_TABLE(
d.json_str,
'$[*]'
ERROR ON ERROR
COLUMNS(
itemid VARCHAR2(20) PATH '$.itemid',
duration VARCHAR2(10) PATH '$.duration',
title VARCHAR2(200) PATH '$.title',
description VARCHAR2(4000) PATH '$.description',
pubdate VARCHAR2(50) PATH '$.pubDate'
)
) j
Which, for the sample data:
CREATE TABLE json_podcast_data (json_str CLOB CHECK (json_str IS JSON ) );
INSERT INTO json_podcast_data ( json_str ) VALUES (
'[
{
"itemid" : "18726539",
"duration" : "19:28",
"title" : "Flight Plan for Trading: Market Lessons from My Pilot Dad",
"description" : "<p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>",
"pubDate" : "Wed, 14 Apr 2021 18:04:19 +0000"
}
]' );
Outputs:
ITEMID
DURATION
TITLE
DESCRIPTION
PUBDATE
18726539
19:28
Flight Plan for Trading: Market Lessons from My Pilot Dad
Learning to fly an airplane can build an excellent structured thought process for navigating markets
2021-04-14 18:04:19.000000 +00:00

You can get the value of the itemid and description using JSON_VALUE. See example below
WITH
json_podcast_data (json_str)
AS
(SELECT '[
{
"itemid" : "18726539",
"duration" : "19:28",
"title" : "Flight Plan for Trading: Market Lessons from My Pilot Dad",
"description" : "<p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>",
"pubDate" : "Wed, 14 Apr 2021 18:04:19 +0000"
}
]'
FROM DUAL)
SELECT json_value (json_str, '$[0].itemid') AS itemid,
json_value (json_str, '$[0].description') AS description
FROM json_podcast_data;
ITEMID DESCRIPTION
___________ ______________________________________________________________________________________________________________
18726539 <p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>
If your JSON array has multiple items in it, you can use the JSON_TABLE function to list all items in the array.
/* Formatted on 27-Jul-2021 5:51:38 PM (QP5 v5.354) */
WITH
json_podcast_data (json_str)
AS
(SELECT '[
{
"itemid" : "18726539",
"duration" : "19:28",
"title" : "Flight Plan for Trading: Market Lessons from My Pilot Dad",
"description" : "<p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>",
"pubDate" : "Wed, 14 Apr 2021 18:04:19 +0000"
},
{
"itemid" : "23456",
"duration" : "10:15",
"title" : "Test Title",
"description" : "<p>Some cool podcast</p>",
"pubDate" : "Wed, 14 Apr 2021 18:04:19 +0000"
}
]'
FROM DUAL)
SELECT j.itemid, j.description
FROM json_podcast_data
CROSS JOIN
JSON_TABLE (
json_str,
'$[*]'
COLUMNS itemid NUMBER PATH '$.itemid', description VARCHAR2 PATH '$.description') j;
ITEMID DESCRIPTION
___________ ______________________________________________________________________________________________________________
18726539 <p>Learning to fly an airplane can build an excellent structured thought process for navigating markets</p>
23456 <p>Some cool podcast</p>

Related

How to parse JSON into relational format in SQL Server 2016?

I have some Json stored in SQL Server 2016 table as under (partitial)
{
"AFP": [
{
"AGREEMENTID": "29040400001330",
"LoanAccounts": {
"Product": "OD003",
"BUCKET": 0,
"ZONE": "MUMBAI ZONE",
"Region": "MUMBAI METRO-CENTRAL REGION",
"STATE": "GOA",
"Year": 2017,
"Month": 10,
"Day": 13
},
"FeedbackInfo": {
"FeedbackDate": "2017-10-13T12:07:44.2317198",
"DispositionDate": "2017-10-13T12:07:44.2317198",
"DispositionCode": "PR"
},
"PaymentInfo": {
"ReceiptNo": "2000000170",
"ReceiptDate": "2017-10-13T12:07:42.1218299",
"PaymentMode": "Cheque",
"Amount": 200,
"PaymentStatus": "CollectionBatchCreated"
}
}
]
}
table schema as under
create table tblHistoricalDataDemo(
AGREEMENTID nvarchar(40)
,Year_Json nvarchar(4000)
)
I would like to fetch the records from JSON into relational format as
AgreementID Product Bucket .... PaymentStatus
I tried with below but something wrong i am doing for which I am not able to get the result
SELECT AGREEMENTID,
JSON_VALUE(Year_Json, '$.LoanAccounts') AS records
FROM tblHistoricalDataDemo
Use the OPENJSON built in table value function:
SELECT *
FROM tblHistoricalDataDemo
CROSS APPLY
OPENJSON(Year_Json, '$.AFP') WITH
(
-- You don't have to specify the json path
-- if the column name is the same as the json name
AGREEMENTID bigint
)
As afp
CROSS APPLY
OPENJSON(Year_Json, '$.AFP') WITH
(
Product varchar(10) '$.LoanAccounts.Product',
bucket int '$.LoanAccounts.BUCKET'
)
As LoanAccounts
In case the array in JSON has a fixed number of element, use
$.P1[x]
If AFP has only 1 element,
SELECT t.AGREEMENTID,
JSON_Value(Year_Json, '$.AFP[0].LoanAccounts.Product') Product,
JSON_Value(Year_Json, '$.AFP[0].LoanAccounts.BUCKET') Bucket,
JSON_Value(Year_Json, '$.AFP[0].PaymentInfo.PaymentStatus') PaymentStatus
FROM tblHistoricalDataDemo t
Run it in SQLFiddle, thx Jacob H.

TSQL Select basic hierarchical data from JSON

This is a rediculously simple question, but I cannot find a single working example anywhere. MSDN hints it is possible (here and here), but misses the actual example, and Google presents a myriad of examples outputting JSON from TSQL, whereas I need the reverse.
Taking a most basic JSON structure:
DECLARE #json nvarchar(max) = N'[{
"Id": 1,
"name": "John",
"skills": [
{"title": "Azure" },
{"title": "VB" },
{"title": "JavaScript" }]
}, {
"Id": 2,
"name": "Jane",
"skills": [
{"title": "Azure" },
{"title": "SQL" },
{"title": "C#" }]
}]';
I figured how to get the highest-level values, such as Id and name:
SELECT
*
FROM
OPENJSON(#json) WITH (
ID int '$.Id',
name nvarchar(50) '$.name'
);
What I'd like is to output PersonId, and the respective skill titles for each, e.g.
PersonId SkillTitle
-----------------------
1 Azure
1 VB
1 JavaScript
2 Azure
2 SQL
2 C#
Google only provides me with the reverse logic. My badly-broken attempt based on what I can find is here:
SELECT
*
FROM
OPENJSON(#json, '$.skills') WITH (
PersonId int './Id',
SkillTitle nvarchar(50) '$.title'
);
The below code snippet would give you the required results -
SELECT
JSON_Value (c.value, '$.Id') as ID,
JSON_Value (p.value, '$.title') as SkillTitle
FROM OPENJSON (#json) as c
CROSS APPLY OPENJSON(c.value,'$.skills') as p
Have implemented the same by CROSS APPLYing the JSON child node with the parent node and using the JSON_Value() function.

fromJSON encoding issue

I try to convert a json object to R dataframe, here is the json object:
json <-
'[
{"Name" : "a", "Age" : 32, "Occupation" : "凡达"},
{"Name" : "b", "Age" : 21, "Occupation" : "打蜡设计费"},
{"Name" : "c", "Age" : 20, "Occupation" : "的拉斯克奖飞"}
]'
then I use fromJSON, mydf <- jsonlite::fromJSON(json), the result is
Name Age Occupation
1 a 32 <U+51E1><U+8FBE>
2 b 21 <U+6253><U+8721><U+8BBE><U+8BA1><U+8D39>
3 c 20 <U+7684><U+62C9><U+65AF><U+514B><U+5956><U+98DE>
I was wondering how this happens, and is there any solution?
Using the package rjson can solve the problem, but the output is a list, but I want a dataframe output.
Thank you.
I've tried Sys.setlocale(locale = "Chinese"), well the characters are indeed Chinese,but the results are still weird like below:
Name Age Occupation
1 a 32 ·²´ï
2 b 21 ´òÀ¯Éè¼Æ·Ñ
3 c 20 µÄÀ­Ë¹¿Ë½±·É

postgres json parse to timestamp

I am trying to get some data into my postgres DB from a CSV file containing a json dump. As long as it is just strings it is alright, but I want my strings containing timestamps to be stored as timestamps in postgres. Soo I need to do some conversion of the two fields:registerdate and dateofbirth. The below code works except for the date conversion lines...
Any clue on how to successfully convert the two strings to timestamps below:
CREATE TABLE users (
id SERIAL,
mongo_id TEXT,
password VARCHAR(128),
firstname VARCHAR(200),
lastname VARCHAR(200),
dateofbirth TIMESTAMP,
registerdate TIMESTAMP,
displayname VARCHAR(200),
language VARCHAR(200),
country VARCHAR(200),
profilepicture VARCHAR(200),
backgroundpicture VARCHAR(200),
type VARCHAR(200),
sex VARCHAR(6),
offlinemode BOOLEAN,
email VARCHAR(200),
friends VARCHAR(255)[]
);
INSERT INTO users (mongo_id, password,firstname,lastname, dateofbirth, registerdate, displayname, language)
SELECT data->>'_id',
data->>'password',
data->>'firstName',
data->>'secondName',
to_timestamp(data->'dateOfBirth'->>'$date'), /*<------*/
to_timestamp(data->'registerDate'->>'$date'), /*<-------*/
data->>'displayName',
data->>'language'
FROM import.mongo_users;
The data format in mongo_users:
{ "_id" : "1164", "password" : "aaa123123", "firstName" : "Adam", "secondName" : "Kowlalski", "dateOfBirth" : { "$date" : "2014-05-18T07:41:09.202+0200" }, "registerDate" : { "$date" : "2016-06-01T12:59:53.941+0200" }, "displayName" : "Adam Kowlalski", "language" : "nb", "country" : null, "profilePicture" : null, "backgroundPicture" : null, "type" : "USER", "sex" : "MALE", "offlineMode" : true, "email" : "bk_1164#test.email", "friends" : [ "KUE" ] }
The to_timestamp function requries two parameters: date_time in text format, and the formatting template.
You don't need to use to_timestamp since your date-time values are already formatted with a valid timestamp, and PostgreSQL understands json-formatted timestamps well enough. The following works well:
SELECT data->>'_id',
data->>'password',
data->>'firstName',
data->>'secondName',
(data->'dateOfBirth'->>'$date')::timestamp, --<< simply cast to timestamp
(data->'registerDate'->>'$date')::timestamp, --<< simply cast to timestamp
data->>'displayName',
data->>'language'
FROM (SELECT
'{ "_id" : "1164", "password" : "aaa123123", "firstName" : "Adam", "secondName" : "Kowlalski", "dateOfBirth" : { "$date" : "2014-05-18T07:41:09.202+0200" },
"registerDate" : { "$date" : "2016-06-01T12:59:53.941+0200" }, "displayName" : "Adam Kowlalski", "language" : "nb", "country" : null, "profilePicture" : null,
"backgroundPicture" : null, "type" : "USER", "sex" : "MALE", "offlineMode" : true, "email" : "bk_1164#test.email", "friends" : [ "KUE" ] }'::jsonb as data) d
Your JSON Date format looks like ISO 8601 (https://en.wikipedia.org/wiki/ISO_8601). For transforming the input string to a date variable you should use the to_date function.
e.g.
to_date(data->'dateOfBirth'->>'$date','YYYY-MM-DD"T"HH24:MI:SS')
Be ware that you have to check if Timezone differences play a role. Postgresql has an option OF: https://www.postgresql.org/docs/current/static/functions-formatting.html
For me this is what worked.
SELECT to_timestamp(nullif(LEFT(dates_json->>'date_prop',10), '')::numeric) as date_extracted FROM table_name
First shrink the value to 10 symbols (if the timestamp include miliseconds), then check if it is null, convert to numeric, then pass it to function to_timestamp().
This way I fixed another error "date/time field value out of range".

converting xml to json using postgresql

I am working on converting XML to j son string using the PostgreSQL.
we have attributecentric XML and would like to know how to convert it to j son.
Example XML:
<ROOT><INPUT id="1" name="xyz"/></ROOT>
Need to get the j son as follows:
{ "ROOT": { "INPUT": { "id": "1", "name": "xyz" }}}
got the above json format from an online tool.
any help or guidance will be appreciated.
Regards
Abdul Azeem
Basically, breakdown of this problem is the following:
extract values from given XML using xpath() function
generate and combine JSON entries using json_object_agg() function
The only tricky thing here is to combine key,value pairs together from xpath()/json_object_agg() results, which are{ "id": "1"} and { "name" : "xyz"}.
WITH test_xml(data) AS ( VALUES
('<ROOT><INPUT id="1" name="xyz"/></ROOT>'::XML)
), attribute_id(value) AS (
-- get '1' value from id
SELECT (xpath('//INPUT/#id',test_xml.data))[1] AS value
FROM test_xml
), attribute_name(value) AS (
-- get 'xyz' value from name
SELECT (xpath('//INPUT/#name',test_xml.data))[1] AS value
FROM test_xml
), json_1 AS (
-- generate JSON 1 {"id": "1"}
SELECT json_object_agg('id',attribute_id.value) AS payload
FROM attribute_id
), json_2 AS (
-- generate JSON 2 {"name" : "xyz"}
SELECT json_object_agg('name',attribute_name.value) AS payload FROM attribute_name
), merged AS (
-- Generate INPUT result - Step 1 - combine JSON 1 and 2 as single key,value source
SELECT key,value
FROM json_1,json_each(json_1.payload)
UNION ALL
SELECT key,value
FROM json_2,json_each(json_2.payload)
), input_json_value AS (
-- Generate INPUT result - Step 2 - use json_object_agg to create JSON { "id" : "1", "name" : "xyz" }
SELECT json_object_agg(merged.key,merged.value) AS data
FROM merged
), input_json AS (
-- Generate INPUT JSON as expected { "INPUT" : { "id" : "1", "name" : "xyz" } }
SELECT json_object_agg('INPUT',input_json_value.data) AS data
FROM input_json_value
)
-- Generate final reult
SELECT json_object_agg('ROOT',input_json.data)
FROM input_json;