Accessing an array object from JSON by index-variable - json

I want to access over an array object in JSON by index with a variable. Consider the following code:
declare #pjson nvarchar(max)='{
"store":{
"storeId": 100,
"name": "TEST",
"lastUpdatedBy": "MULE",
"location": {
declare #pjson nvarchar(max)='{
"store":{
"storeId": 100,
"name": "TEST",
"lastUpdatedBy": "MULE",
"location": {
"addresses": [
{
"addressType": "MAIN",
"name": "Name1",
"name2": "Name2",
"address": "Address1",
"address2": "Address2",
"city": "City",
"lastUpdateBy": "MULE"
},
{
"addressType": "SECONDARY",
"name": "Name1",
"name2": "Name2",
"address": "Address1",
"address2": "Address2",
"city": "City",
"lastUpdateBy": "MULE"
},
{
"addressType": "BILLING",
"name": "Name1",
"name2": "Name2",
"address": "Address1",
"address2": "Address2",
"city": "City",
"lastUpdateBy": "MULE"
}
]
}
}
}'
Declare #counter1 INT = 0;
Print JSON_VALUE(#pjson,N'lax $.store.location.addresses[#counter1].addressType')
I get an error:
JSON path is not properly formatted. Unexpected character '#' is found
at position 31.
If I try directly by passing number as
Declare #counter1 INT = 0;
Print JSON_VALUE(#pjson,N'lax $.store.location.addresses[0].addressType')
I get the expected result
MAIN
Is there something that I am missing while passing the variable?

I don't think that you can use a T-SQL variable directly as part of the path parameter in the JSON_VALUE() call, but you may try one of the following approaches:
Concatenate the #counter variable in the path parameter (SQL Server 2017 is needed).
Parse the JSON with OPENJSON() and the appropriate WHERE clause.
JSON:
DECLARE #counter INT = 0;
DECLARE #pjson nvarchar(max) = N'{
"store":{
"storeId":100,
"name":"TEST",
"lastUpdatedBy":"MULE",
"location":{
"addresses":[
{
"addressType":"MAIN",
"name":"Name1",
"name2":"Name2",
"address":"Address1",
"address2":"Address2",
"city":"City",
"lastUpdateBy":"MULE"
},
{
"addressType":"SECONDARY",
"name":"Name1",
"name2":"Name2",
"address":"Address1",
"address2":"Address2",
"city":"City",
"lastUpdateBy":"MULE"
},
{
"addressType":"BILLING",
"name":"Name1",
"name2":"Name2",
"address":"Address1",
"address2":"Address2",
"city":"City",
"lastUpdateBy":"MULE"
}
]
}
}
}'
Statement with variable concatenation:
SELECT JSON_VALUE(
#pjson,
CONCAT(N'lax $.store.location.addresses[', #counter, N'].addressType')
)
Statement with OPENJSON():
SELECT JSON_VALUE([value], '$.addressType')
FROM OPENJSON(#pjson, 'lax $.store.location.addresses')
WHERE CONVERT(int, [key]) = #counter
Result:
(No column name)
----------------
MAIN

Try following:
DECLARE #pJson NVARCHAR(4000)
-- ...
DECLARE #Counter INT = 0
DECLARE #PathString NVARCHAR(1000)
SET #PathString = N'lax $.store.location.addresses[' + CAST(#Counter AS NVARCHAR(50)) + N'].addressType'
PRINT JSON_VALUE(#Pjson,#PathString)

Related

apex_json.get_varchar2 not extract values from json response of SOAP API

I am trying to extract values in PLSQL from json response which came from SOAP API response,
JSON response:
{
"#xmlns:SOAP-ENV": "http://test",
"SOAP-ENV:Header": null,
"SOAP-ENV:Body": {
"ProcessShipmentReply": {
"#xmlns": "http://test.com/",
"HighestSeverity": "WARNING",
"Notifications": {
"Severity": "WARNING",
"Source": "ship",
"Code": "7033"
},
"TransactionDetail": {
"CustomerTransactionId": "12345655"
},
"Version": {
"ServiceId": "ship",
"Major": "28",
"Intermediate": "0",
"Minor": "0"
},
"JobId": "1231561",
"RequiredDetail": {
"UsDomestic": "false",
"CarrierCode": "test",
"MasterTrackingId": {
"TrackingIdType": "test",
"FormId": "0430",
"TrackingNumber": "456413421"
}
}
}
}
}
PLSQL by which I am trying to extract values from json:
APEX_JSON.parse(RESP);
P_TRACK_NO := APEX_JSON.get_varchar2('SOAP-ENV:Body.ProcessShipmentReply.RequiredDetail.MasterTrackingId.TrackingNumber');
I have done this many times for other API response and doing the same with this but I think due to SOAP API response I am unable to get the same results as I am getting for other API.
Please suggest me, how can I extract values from this JSON response.
I suppose the ":" in the json key "SOAP-ENV:Body" is throwing it off so best to enclose it in double qoutes:
SET SERVEROUTPUT ON
DECLARE
l_json_text VARCHAR2(32767);
l_json_values apex_json.t_values;
BEGIN
l_json_text := '
{
"#xmlns:SOAP-ENV": "http://test",
"SOAP-ENV:Header": null,
"SOAP-ENV:Body": {
"ProcessShipmentReply": {
"#xmlns": "http://test.com/",
"HighestSeverity": "WARNING",
"Notifications": {
"Severity": "WARNING",
"Source": "ship",
"Code": "7033"
},
"TransactionDetail": {
"CustomerTransactionId": "12345655"
},
"Version": {
"ServiceId": "ship",
"Major": "28",
"Intermediate": "0",
"Minor": "0"
},
"JobId": "1231561",
"RequiredDetail": {
"UsDomestic": "false",
"CarrierCode": "test",
"MasterTrackingId": {
"TrackingIdType": "test",
"FormId": "0430",
"TrackingNumber": "456413421"
}
}
}
}
}
';
apex_json.parse(
p_values => l_json_values,
p_source => l_json_text
);
DBMS_OUTPUT.put_line('----------------------------------------');
if apex_json.does_exist(p_path => '"SOAP-ENV:Body".ProcessShipmentReply.RequiredDetail.MasterTrackingId.TrackingNumber',p_values => l_json_values) then
dbms_output.put_line(apex_json.get_number(p_path => '"SOAP-ENV:Body".ProcessShipmentReply.RequiredDetail.MasterTrackingId.TrackingNumber', p_values => l_json_values));
end if;
DBMS_OUTPUT.put_line('----------------------------------------');
END;
/
----------------------------------------
456413421
----------------------------------------
PL/SQL procedure successfully completed.

Can't get access to data from nested json's array

How to retrieve values from employment_types (type, salary) and skills (name, level) arrays and show them in columns? I tried with employment_types and it doesn't work not to mention skills:
declare #json nvarchar(max)
set #json = '[
{
"title": "IT Admin",
"experience_level": "mid",
"employment_types": [
{
"type": "permanent",
"salary": null
}
],
"skills": [
{
"name": "Security",
"level": 3
},
{
"name": "WIFI",
"level": 3
},
{
"name": "switching",
"level": 3
}
]
},
{
"title": "Lead QA Engineer",
"experience_level": "mid",
"employment_types": [
{
"type": "permanent",
"salary": {
"from": 7000,
"to": 13000,
"currency": "pln"
}
}
],
"skills": [
{
"name": "Embedded C",
"level": 4
},
{
"name": "Quality Assurance",
"level": 4
},
{
"name": "C++",
"level": 4
}
]
}
]';
SELECT *
FROM OPENJSON(#JSON, '$.employment_types')
WITH
(
type nvarchar(50) '$.type',
salary varchar(max) '$.salary'
)
There are almost 7000 records and I'd like to show mentioned above columns from all of them.
It's hard to know exactly what you want, given that both employment_types and skills are arrays. But assuming employment_types always has only one element, you could do something like this
SELECT
j1.title,
j1.experience_level,
j1.employment_type,
salary = j1.salary_currency + ' ' + CONCAT(j1.salary_from, ' - ', j1.salary_to),
j2.name,
j2.level
FROM OPENJSON(#JSON)
WITH (
title nvarchar(100),
experience_level nvarchar(10),
employment_type nvarchar(50) '$.employment_types[0].type',
salary_from int '$.employment_types[0].salary.from',
salary_to int '$.employment_types[0].salary.to',
salary_currency char(3) '$.employment_types[0].salary.currency',
skills nvarchar(max) AS JSON
) j1
CROSS APPLY OPENJSON(j1.skills)
WITH
(
name nvarchar(50),
level int
) j2
db<>fiddle
Since we are pulling data directly from the root object, we don't need a JSON path argument. OPENJSON will automatically break out an array into separate rows. If you just wanted employment_types, you could go directly to that with a path argument.
employment_types[0] means to only get the first element of the array. If you want all the elements, you will need another OPENJSON
Note the use of AS JSON for skills, this means that the entire JSON array is pulled out, and can then be pushed through another call to OPENJSON

Get Children nodes in json string using sql stored procedure?

I have a JSON string passed into stored procedure as follows,
{"config": {
"site": "Internal",
"library": "test-library",
"folderHierarchy": {
"name": "folder1",
"children": {
"name": "folder2",
"children": {
"name": "folder3"
}
}
},
"meta_data": [{
"meta_text": "date-created",
"meta_value": "2020-04-17"
}, {
"meta_text": "date-modified",
"meta_value": "2020-04-17"
}]
}}
I need to get folder names inside folderHierarchy node , it can have many number or folders inside as children.
First I tried to get folderHierarchy as a JSON string and iterate through that JSON string.
DECLARE #CONFIG VARCHAR(MAX) = '{"config": {
"site": "Internal",
"library": "test-library",
"folderHierarchy": {
"name": "folder1",
"children": {
"name": "folder2",
"children": {
"name": "folder3"
}
}
},
"meta_data": [{
"meta_text": "date-created",
"meta_value": "2020-04-17"
}, {
"meta_text": "date-modified",
"meta_value": "2020-04-17"
}]
}}'
DECLARE #folderHierarchy VARCHAR(MAX);
SET #folderHierarchy = JSON_QUERY(#CONFIG, '$.config.folderHierarchy');
SELECT #folderHierarchy;
SELECT *
FROM openjson(#folderHierarchy)
WITH(
name VARCHAR(max) '$.name',
childern NVARCHAR(MAX) '$.children' AS JSON
) AS P
OUTER APPLY OPENJSON(P.childern)
WITH (name NVARCHAR(MAX) '$.name');
But this give me the first and second folder names.
Can anyone help me to get all the folder names, the main thing is I haven't control about number of child item in a folder.
I mean folder1 can have folder called folder2, and folder 2 can have folder called folder 3, and folder3 can have folder called folder4 etc.. etc..
You could use a Recursive CTE for this. The default settings on SQL Server will allow you to recurse up to 100 levels deep (see MAXRECUSRION)...
declare #Config nvarchar(max) =
N'{"config": {
"site": "Internal",
"library": "test-library",
"folderHierarchy": {
"name": "folder1",
"children": {
"name": "folder2",
"children": {
"name": "folder3"
}
}
},
"meta_data": [{
"meta_text": "date-created",
"meta_value": "2020-04-17"
}, {
"meta_text": "date-modified",
"meta_value": "2020-04-17"
}]
}}';
with JsonFolders as (
select
1 as level,
name,
children
from openjson(#Config, N'$.config.folderHierarchy') with (
name nvarchar(max) N'$.name',
children nvarchar(max) N'$.children' as json
)
union all
select
1 + level,
Child.name,
Child.children
from JsonFolders JF
cross apply openjson(JF.children) with (
name nvarchar(max) N'$.name',
children nvarchar(max) N'$.children' as json
) Child
)
select * from jsonFolders;

How can I loop through array of json in SQL Server?

I want to loop through data to get taggedEntityName and taggedEntityId:
{
"data": [
{
"taggedEntityName": "Organization",
"taggedEntityId": [
145642,
145625
],
"index": 0
},
{
"taggedEntityName": "Job",
"taggedEntityId": [
221138
],
"index": 1
}
]
}
If you use SQL Server 2016+, you need to use OPENJSON() to parse the input JSON. The structure of the input JSON is always important and in this specific case you need to use OPENSJON() with explicit schema twice:
JSON:
DEClARE #json nvarchar(max) = N'{
"data": [
{
"taggedEntityName": "Organization",
"taggedEntityId": [
145642,
145625
],
"index": 0
},
{
"taggedEntityName": "Job",
"taggedEntityId": [
221138
],
"index": 1
}
]
}'
Statement:
SELECT j1.taggedEntityName, j2.taggedEntityId
FROM OPENJSON(#json, '$.data') WITH (
taggedEntityName varchar(50) '$.taggedEntityName',
taggedEntityId nvarchar(max) '$.taggedEntityId' AS JSON
) j1
CROSS APPLY OPENJSON(j1.taggedEntityId) WITH (
taggedEntityId int '$'
) j2
Result:
taggedEntityName taggedEntityId
Organization 145642
Organization 145625
Job 221138

How to properly unpack a JSON array in SQL Server

I'm making a foray into JSON, I'd like to add a user to multiple groups: insert an JSON array into a table.
Ideally, the JSON would look like this:
'{
"Email": "WMogh#starfleet.gov",
"Prefix":null,
"FirstName": "Worf",
"MiddleInitial": "",
"LastName": "Mogh",
"Suffix": "Son Of",
"Title" :"Commander",
"Groups": [{"0", "1", "5"}]
"Better_Groups": [{"ID":"0", "ID":"1", "ID":"5"}]
}'
Currently, I can do it with JSON like this:
'{
"Email": "WMogh#starfleet.gov",
"Prefix":null,
"FirstName": "Worf",
"MiddleInitial": "",
"LastName": "Mogh",
"Suffix": "Son Of",
"Title" :"Commander",
"Groups": "1,2,3,4"
}'
then "unpack" it with the following ditty:
declare #groups varchar(1000)
select #groups = Groups from openjson(#json)
WITH
(
Groups nvarchar(100) '$.Groups'
)
print #groups
select value from string_split(#groups, ',')
which returns a nice little table like so:
Value
1
2
3
4
Problem This is bad JSON and the Web developer will make fun of me.
Question How do you propely unpack a JSON array in SQL Server?
update:
The final JSON used looks like so:
#json =
'{
"Email": "WMogh#starfleet.gov",
"Prefix":null,
"FirstName": "Worf",
"MiddleInitial": "",
"LastName": "Mogh",
"Suffix": "Son Of",
"Title" :"Commander",
"Groups": "1,2,3,4",
"Better_Groups": ["0", "1", "5"]
}'
Assuming that "groups" element is an array:
DECLARE #json NVARCHAR(MAX) =
N'{
"Email": "WMogh#starfleet.gov",
"Prefix":null,
"FirstName": "Worf",
"MiddleInitial": "",
"LastName": "Mogh",
"Suffix": "Son Of",
"Title" :"Commander",
"Better_Groups": ["0", "1", "5"]
}';
SELECT s.value
FROM OPENJSON(JSON_QUERY(#json, '$.Better_Groups')) s;
db<>fiddle demo