Update JSON array using SQL Server - sql

I have JSON like below:
{
"property": {
"commonProperty": "abc",
"Items": [
{
"ID": 1,
"Name": "a"
},
{
"ID": 2,
"Name": "a"
},
{
"ID": 3,
"Name": "b"
}
]
}
}
And what I want to achieve is to update Names to "c" where it's currently "a" using SQL Server (so I want to have result like below).
{
"property": {
"commonProperty": "abc",
"Items": [
{
"ID": 1,
"Name": "c"
},
{
"ID": 2,
"Name": "c"
},
{
"ID": 3,
"Name": "b"
}
]
}
}
As far as I know I cannot use JSON_MODIFY because it does not handles queries inside it's arguments and OPENJSON cannot be updated. Is there any method I can use?
EDIT note: added common property above Items.

You may try one of the following options:
Parse the '$.property.Items' JSON array as table using OPENJSON(), make an update, output the table's content as JSON using FOR JSON and modify the original JSON using JSON_MODIFY():
Build a dynamic statement. You can modify the input JSON using JSON_MODIFY() and the appropriate path. The path needs to be defined as a literal or from SQL Server 2017 as a variable, but using a wildcard is not possible (e.g. the statement SELECT #json = JSON_MODIFY(#json, '$.property.Items[0].Name', N'c') modifies the first item in the Items JSON array).
JSON:
DECLARE #json nvarchar(max) = N'{
"property":{
"commonProperty":"abc",
"Items":[
{
"ID":1,
"Name":"a"
},
{
"ID":2,
"Name":"a"
},
{
"ID":3,
"Name":"b"
}
]
}
}'
Statement (that parses the JSON as a table, modifies the table and outputs the table's content as JSON):
SELECT #json = JSON_MODIFY(
#json,
'$.property.Items',
(
SELECT
ID AS 'ID',
CASE WHEN Name = N'a' THEN N'c' ELSE Name END AS 'Name'
FROM OPENJSON(#json, '$.property.Items') WITH (ID int, Name nvarchar(50))
FOR JSON PATH
)
)
Dynamic statement:
DECLARE #stm nvarchar(max)
SET #stm = (
SELECT N'SET #json = JSON_MODIFY(#json, ''$.property.Items[' + [key] + N'].Name'', N''c''); '
FROM OPENJSON(#json, '$.property.Items')
WHERE JSON_VALUE([value], '$.Name') = N'a'
FOR XML PATH('')
)
PRINT #stm
EXEC sp_executesql #stm, N'#json nvarchar(max) OUTPUT', #json OUTPUT

Related

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

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

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

get Json values and Json string from Json Array in SQL Server

I have a JSON string like this:
{
"success": "true",
"data": [
{ "ID": 1, "name": "abc" },
{ "ID": 2, "name": "def" }
]
}
I need output like below:
ID
name
JsonString
1
abc
{"ID": 1, "name": "abc"}
2
def
{"ID": 2, "name": "def"}
I need the query in SQL Server
The only interesting things here are the initial path to OPENJSON (since we only care about data) and the property JsonString reflecting the original JSON, which needs a path and an override.
DECLARE #json NVARCHAR(MAX) = '{"success":"true","data":[{"ID":1,"name":"abc"},{"ID":2,"name":"def"}]}';
SELECT *
FROM OPENJSON(#json, '$.data')
WITH (ID INT, name VARCHAR(100), JsonString NVARCHAR(MAX) '$' AS JSON)

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

Reading json array into rows in SQL Server

Given the sample json data below, how can I write a query to pull the array data all in one step? My goal is to have one row for each item in the ActionRecs array (4). My actual json is more complicated but I think this gives a good example of my goal.
declare #json2 nvarchar(max)
set #json2 = '{
"RequestId": "1",
"ActionRecs": [
{
"Type": "Submit",
"Employee": "Joe"
},
{
"Type": "Review",
"Employee": "Betty"
},
{
"Type": "Approve",
"Employee": "Sam"
},
{
"Type": "Approve",
"Employee": "Bill"
}
]
}'
SELECT x.*
, JSON_QUERY(#json2, '$.ActionRecs') as ActionArray
from OPENJSON(#json2)
with (Id varchar(5) '$.RequestId') as x
One possible approach is to use OPENJSON() with explicit schema and an additional CROSS APPLY operator:
DECLARE #json nvarchar(max)
SET #json = N'{
"RequestId": "1",
"ActionRecs": [
{"Type": "Submit", "Employee": "Joe"},
{"Type": "Review", "Employee": "Betty"},
{"Type": "Approve", "Employee": "Sam"},
{"Type": "Approve", "Employee": "Bill"}
]
}'
SELECT i.Id, a.[Type], a.[Employee]
FROM OPENJSON(#json) WITH (
Id varchar(5) '$.RequestId',
ActionRecs nvarchar(max) '$.ActionRecs' AS JSON
) AS i
CROSS APPLY OPENJSON(i.ActionRecs) WITH (
[Type] nvarchar(max) '$.Type',
[Employee] nvarchar(max) '$.Employee'
) a
Output:
Id Type Employee
1 Submit Joe
1 Review Betty
1 Approve Sam
1 Approve Bill