Select from json data is resulting in null values. How to select from this simple json data - sql

I have the following JSON data:
declare #json nvarchar(max)=
'
[{
"images": [{
"key": "c:\\stapler\\booktest\\gray00024.jp2",
"imageNumber": 1
}],
"instrumentNumber": 94109416
},
{
"images": [{
"key": "c:\\stapler\\booktest\\gray00025.jp2",
"imageNumber": 1
},
{
"key": "c:\\stapler\\booktest\\gray00026.jp2",
"imageNumber": 2
}
],
"instrumentNumber": 94109417
},
{
"images": [{
"key": "c:\\stapler\\booktest\\gray00027.jp2",
"imageNumber": 1
},
{
"key": "c:\\stapler\\booktest\\gray00028.jp2",
"imageNumber": 2
}
],
"instrumentNumber": 94109418
}
]'
I am trying to pull the key and imageNumber from each of these records.
I have tried this query which will give me the instrument number, but gives NULL skey and imageNumber values:
select * from openjson (#json)
with(
instrumentNumber nvarchar(100) '$.instrumentNumber',
skey nvarchar(500) '$.images.key',
imageNumber nvarchar(500) '$.images.imageNumber')
Can anyone tell me what I am doing wrong?

Because you have a nested array (images) you need to extract those values in another openjson which you can then cross apply to the original:
select a.instrumentNumber, b.skey, b.imageNumber
from openjson (#json)
with (
instrumentNumber nvarchar(100) '$.instrumentNumber',
images nvarchar(max) as json
) a
cross apply openjson (a.images)
with (
skey nvarchar(500) '$.key',
imageNumber nvarchar(500) '$.imageNumber'
) b
Output for your sample data
instrumentNumber skey imageNumber
94109416 c:\stapler\booktest\gray00024.jp2 1
94109417 c:\stapler\booktest\gray00025.jp2 1
94109417 c:\stapler\booktest\gray00026.jp2 2
94109418 c:\stapler\booktest\gray00027.jp2 1
94109418 c:\stapler\booktest\gray00028.jp2 2
Demo on dbfiddle.uk

Related

SQL Server OPENJSON read nested JSON same key array

I am following the idea from Ed.Schavelev on article 'SQL Server OPENJSON read nested json'. But I need instead of repeating the rows I wanted them (4) to be in the columns. Is this possible?
I have tried as below:
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{
"EmployeeScheduleXRefCode":"#DF_10212",
"EmployeeXRefCode":"7274",
"TimeStart":"2022-10-31T05:30:00",
"TimeEnd":"2022-10-31T15:30:00",
"Published":false,
"Breaks":[
],
"Activities":[
],
"Skills":[
],
"LaborMetrics":[
{
"CodeXRefCode":"MEDIUM",
"TypeXRefCode":"ACUITY_LM"
},
{
"CodeXRefCode":"ATA",
"TypeXRefCode":"EMPLOYEE_TYPE_LM"
},
{
"CodeXRefCode":"BM02KR",
"TypeXRefCode":"TEAM_NAME_LM"
},
{
"CodeXRefCode":"AV_LM",
"TypeXRefCode":"JOB_TYPE_LM"
}
],
"Segments":[
]
},
{
"EmployeeScheduleXRefCode":"#DF_10200",
"EmployeeXRefCode":"7269",
"TimeStart":"2022-10-31T05:30:00",
"TimeEnd":"2022-10-31T15:30:00",
"Published":false,
"Breaks":[
],
"Activities":[
],
"Skills":[
],
"LaborMetrics":[
{
"CodeXRefCode":"MEDIUM",
"TypeXRefCode":"ACUITY_LM"
},
{
"CodeXRefCode":"ATA",
"TypeXRefCode":"EMPLOYEE_TYPE_LM"
},
{
"CodeXRefCode":"BM01KR",
"TypeXRefCode":"TEAM_NAME_LM"
},
{
"CodeXRefCode":"AV_LM",
"TypeXRefCode":"JOB_TYPE_LM"
}
],
"Segments":[
]
}
]'
SELECT Shifts.*,LaborMetrics.* FROM
OPENJSON ( #json )
WITH (
EmployeeScheduleXRefCode varchar(200) '$.EmployeeScheduleXRefCode' ,
EmployeeXRefCode varchar(200) '$.EmployeeXRefCode',
TimeStart Datetime '$.TimeStart',
TimeEnd Datetime '$.TimeEnd',
LaborMetrics nvarchar(max) as json
) as Shifts
cross apply openjson (Shifts.LaborMetrics)
with
(
CodeXRefCode nvarchar(100),
TypeXRefCode nvarchar(100)
) as LaborMetrics
But the result is repeating 4 rows and I want them to have them in 4 different columns in a single row.

insert json to sql table getting null

I have the following json , when i am trying to extract it to sql i get empty.
I need CusP.id, CusP.custldId ,cusfield.id, value
DECLARE #json NVARCHAR(MAX);
SELECT #json = '{
"includ": {
"cusP": {
"542310": {
"id": 542310,
"custldId": 155,
"cusfield": {
"id": 155,
"type": "custfi"
},
"projectId": 17435,
"project": {
"id": 17435,
"type": "projects"
},
"value": "META DATA",
"createdAt": "2022-01-16T05:11:20Z",
"createdBy": 222222
},
"21000": {
"id": 21000,
"custldId": 426,
"cusfield": {
"id": 426,
"type": "custfi"
},
"projectId": 786044,
"project": {
"id": 786044,
"type": "projects"
},
"value": "delta55",
"createdAt": "2022-01-17T10:03:07Z",
"createdBy": 333333
}
}
}
}'
This is what i am trying:
SELECT
D.cusPid,
d.[value],
c.cusfieldid,
cd.projectId
FROM OPENJSON(#json, '$.includ.cusP')
WITH (
cusPid NVARCHAR(max) '$.id',
[value] NVARCHAR(max) '$.value'
) D
CROSS APPLY OPENJSON(#json, '$.includ.cusP.custfi')
WITH (
cusfieldid VARCHAR(100) '$.id'
) C
CROSS APPLY OPENJSON(#json, '$.includ.cusP.project')
WITH (
projectId VARCHAR(100) '$.id'
) Cd;
that is the result i expect
cusPid
value
cusfieldid
projectId
542310
META DATA
155
17435
21000
delta55
426
786044
The problem is that the ID is also itself used as the key for a sub-property and OPENJSON does not allow variable paths (beyond arrays), so you need an extra level:
SELECT P.id AS cuspID, P.[value], P.cusfieldid, [projectId]
FROM OPENJSON(#json, '$.includ.cusP') J
CROSS APPLY OPENJSON(J.[value]) WITH (
id INT,
[value] NVARCHAR(MAX),
[projectId] INT,
cusfieldid INT '$.cusfield.id'
) P

Is there an UPDATE equivalent command to SELECT json data

Is there a way to update the data retrieved from the below select (in this case, change "MS220" to something else)? It's difficult enough to do select from JSON in some cases. I'm not sure how to update just a single element.
CREATE TABLE JData (
JsonData nvarchar(max)
)
INSERT INTO JData
(JsonData)
VALUES
('[
{
"Categories": [
{
"QuerySourceNames": [
"QAsset"
],
"Id": "eceae85a-ffc6-49f4-8f6a-78ce2b4b274e",
"Name": "emsdba"
}
],
"Id": "525b4f07-0f67-43ac-8070-a0e6c1ceb1b9",
"Name": "MS220"
}
]')
SELECT
ParamName
FROM [dbo].[JData] jsonData
CROSS APPLY OPENJSON (jsonData)
WITH
(
Categories nvarchar(max) AS json,
Id uniqueidentifier,
ParamName varchar(10) '$.Name'
);
Try JSON_MODIFY() with the path '$[0].Name'
UPDATE d
SET jsonData = JSON_MODIFY(jsonData, '$[0].Name', 'New Value')
FROM [dbo].[JData] d
Results:
[
{
"Categories": [
{
"QuerySourceNames": [
"QAsset"
],
"Id": "eceae85a-ffc6-49f4-8f6a-78ce2b4b274e",
"Name": "emsdba"
}
],
"Id": "525b4f07-0f67-43ac-8070-a0e6c1ceb1b9",
"Name": "New Value"
}
]
db<>fiddle here

Transform properties from JSON array into comma-separated string

I have a string column in an SQL-Server table on Azure which contains the following data:
{
"status": "success",
"data": [
{
"name": "Jane",
"type": 0
},
{
"name": "John",
"type": 0
}
]
}
How can it be transformed into a comma-separated string containing "Jane, John"?
Here how to achieve this via a snippet of some of my older code, you should be able to loop through the table and do this for each row. There may be a quicker way of doing it but this will work.
DECLARE #JSON NVARCHAR(200) = '{"status": "success", "data": [{"name": "Jane", "type": 0},{"name": "John", "type": 0}]}',
#result nvarchar(max) = ''
SELECT #result = #result + [value] + N', '
FROM (
SELECT DISTINCT data.value
FROM OPENJSON(#JSON, '$.data') as jsondata
CROSS APPLY OPENJSON(jsondata.value) as data
WHERE data.[key] = 'name') a
select #result = substring(#result, 1, (LEN(#result)-1))
select #result

SQL Query to get the Json inside Json values by comma separated

I have the below Json object. I need to get the task names by comma (,) separated.
{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC",
"Task" : [
{
TaskID : 1222,
Name: "TaskA"
},
{
TaskID : 154,
Name: "TaskB"
}
]
},
{
"ID": 11,
"Name": "ABCD",
"Task" : [
{
TaskID : 222,
Name: "TaskX"
},
{
TaskID : 234,
Name: "TaskY"
}
]
},
]
}]}
The expected Output should be in the below table. I need the task names should be comma separated.
ModelName ObjectID ObjectName TaskName
Test Model 1 ABC TaskA, TaskB
Test Model 11 ABCD TaskX, TaskY
I tried the below query. But I don't know how to group Task names.
SELECT S1.ModelName,
S2.ID AS ObjectID,
S2.Name AS ObjectName,
S3.TaskName
FROM TableA
CROSS APPLY OPENJSON(JsonData)
WITH (Model NVARCHAR(MAX) '$.Model[0]' AS JSON) S1
CROSS APPLY OPENJSON (S1.Model)
WITH (Object NVARCHAR(MAX) '$.Object' AS JSON,
ID INT '$.ID',
Name NVARCHAR(250) '$.Name') S2
CROSS APPLY OPENJSON (S2.Object)
WITH (Task NVARCHAR(MAX) '$.Task' AS JSON ,
TaskName NVARCHAR(MAX) '$.TaskName') S3
You need to use STRING_AGG() to aggregate the text values and one possible approach (based on the attempt in the question) is the following statement. The aggregation of the task names is for each item in the Object JSON array:
Table:
CREATE TABLE TableA (JsonData varchar(max))
INSERT INTO TableA (JsonData) VALUES ('{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC",
"Task" : [
{
"TaskID" : 1222,
"Name": "TaskA"
},
{
"TaskID" : 154,
"Name": "TaskB"
}
]
},
{
"ID": 11,
"Name": "ABCD",
"Task" : [
{
"TaskID" : 222,
"Name": "TaskX"
},
{
"TaskID" : 234,
"Name": "TaskY"
}
]
}
]
}]}')
Statement:
SELECT
j1.ModelName,
j2.ObjectID, j2.ObjectName,
c.TaskName
FROM TableA t
CROSS APPLY OPENJSON(t.JsonData, '$.Model[0]') WITH (
ModelName varchar(50) '$.ModelName',
Object nvarchar(max) '$.Object' AS JSON
) j1
CROSS APPLY OPENJSON(j1.Object, '$') WITH (
ObjectID int '$.ID',
ObjectName varchar(50) '$.Name',
Task nvarchar(max) '$.Task' AS JSON
) j2
CROSS APPLY (
SELECT STRING_AGG([Name], ',') AS TaskName
FROM OPENJSON (j2.Task, '$') WITH (Name varchar(50) '$.Name')
) c
You need to use STRING_AGG() function, which applies to the DB version SQL Server 2017 and later, together with the below GROUP BY expression as
SELECT S1.ModelName, S2.ID AS ObjectID, S2.Name AS ObjectName,
STRING_AGG(S3.TaskName, ',') WITHIN GROUP (ORDER BY TaskName) AS TaskName
FROM <rest of your query>
GROUP BY S1.ModelName, S2.ID, S2.Name
as a complete query :
SELECT S1.ModelName, S3.ObjectID, S3.ObjectName,
STRING_AGG(S4.TaskName, ',') WITHIN GROUP (ORDER BY S4.TaskName) AS TaskName
FROM TableA
CROSS APPLY OPENJSON(JsonData)
WITH (ModelName NVARCHAR(255) '$.Model[0].ModelName') S1
CROSS APPLY OPENJSON (JsonData)
WITH (Object NVARCHAR(MAX) '$.Model[0].Object' AS JSON) S2
CROSS APPLY OPENJSON (S2.Object)
WITH (ObjectID INT '$.ID',
ObjectName NVARCHAR(255) '$.Name',
Task NVARCHAR(MAX) '$.Task' AS JSON) S3
CROSS APPLY OPENJSON (S3.Task)
WITH (TaskID NVARCHAR(MAX) '$.TaskID',
TaskName NVARCHAR(MAX) '$.Name') S4
GROUP BY S1.ModelName, S3.ObjectID, S3.ObjectName
Using WITHIN GROUP (ORDER BY TaskName) is optional, if you do not want ordering, then you can remove that part from the function as in the below demonstration :
Demo