DECLARE @jsontable TABLE (JsonData nvarchar(max) NULL)
DECLARE @JsonData NVARCHAR(MAX) = N'
{
"Sections": {
"SectionType": false,
"SectionName": "Section1"
},
"MultiOptions": [
{
"Customers": {
"CustomerName": "name1",
"Address": "",
"Source1" : "1"
},
"Orders": {
"OrderName": "item1",
"Qty": 1,
"Dest1" : "0",
"PurchasedQty" : "0"
},
"IsMainOption": true
},
{
"Customers": {
"CustomerName": "name2",
"Address": "",
"Source1" : "2"
},
"Orders": {
"OrderName": "item2",
"Qty": 2,
"Dest1" : "0",
"PurchasedQty" : "0"
},
"IsMainOption": false
},
{
"Customers": {
"CustomerName": "name3",
"Address": "",
"Source1" : "3"
},
"Orders": {
"OrderName": "item2",
"Qty": 3,
"Dest1" : "0",
"PurchasedQty" : "0"
},
"IsMainOption": false
}
],
"DateUpdated": "2022-05-24",
"WhoUpdated": 1
}'
INSERT INTO @jsontable
SELECT @JsonData
;WITH cte AS
(
SELECT
MultiOptions.[key] AS MultiOptionsKey,
MultiOptionsCustomers.[key] AS MultiOptionsCustomersKey,
MultiOptionsCustomers.[value] AS MultiOptionsCustomersValue,
MultiOptionsOrders.[key] AS MultiOptionsOrdersKey,
MultiOptionsOrders.[value] AS MultiOptionsOrdersValue,
JsonData
FROM
@jsontable a
CROSS APPLY
OPENJSON(JsonData, '$.MultiOptions') MultiOptions
CROSS APPLY
OPENJSON(MultiOptions.value, '$.Customers') MultiOptionsCustomers
CROSS APPLY
OPENJSON(MultiOptions.value, '$.Orders' ) AS MultiOptionsOrders
)
UPDATE cte
SET JsonData = JSON_MODIFY(JsonData, '$.MultiOptions[' MultiOptionsKey '].Customers[' MultiOptionsCustomersKey '].Orders[' MultiOptionsOrdersKey '].PurchasedQty', 'Qty#Value')
--select * from cte;
I'm getting this error:
The argument 2 of the "JSON_MODIFY" must be a string literal.
when I execute this query.
I need to update below for all items inside array:
UPDATE [MultiOptions.Orders.Dest1] = [MultiOptions.Customers.Source1]
UPDATE [MultiOptions.Customers.PurchasedQty] = [MultiOptions.Customers.Qty]
CodePudding user response:
I don't think you can use wild cards to modify the JSON content. In your case a possible solution is to parse the stored JSON content (using OPENJSON()) and rebuild the JSON again (uisng FOR JSON PATH):
UPDATE @jsontable
SET JsonData = JSON_MODIFY(
JsonData,
'$.MultiOptions',
(
SELECT
CustomerName AS [Customers.CustomerName],
Address AS [Customers.Address],
Source1 AS [Customers.Source1],
OrderName AS [Orders.OrderName],
Qty AS [Orders.Qty],
Source1 AS [Orders.Dest1], -- updated value
Qty AS [Orders.PurchasedQty], -- updated value
IsMainOption AS [IsMainOption]
FROM OPENJSON(JsonData, '$.MultiOptions') WITH (
CustomerName nvarchar(max) '$.Customers.CustomerName',
Address nvarchar(max) '$.Customers.Address',
Source1 nvarchar(max) '$.Customers.Source1',
OrderName nvarchar(max) '$.Orders.OrderName',
Qty int '$.Orders.Qty',
IsMainOption bit '$.IsMainOption'
)
FOR JSON PATH
)
)
CodePudding user response:
You don't necessarily have to rebuild the whole JSON. In your case, because you only have one level of arrays to feed through OPENJSON, you can just rebuild that, and use JSON_VALUE and JSON_MODIFY to access the various values.
Unfortunately, SQL Server does not have JSON_AGG. So to aggregate whole JSON objects you need STRING_AGG to aggregate, and also JSON_QUERY to prevent double-escaping
UPDATE t
SET JsonData =
JSON_MODIFY(
JsonData,
'$.MultiOptions',
JSON_QUERY((
SELECT
'[' STRING_AGG(
JSON_MODIFY(
JSON_MODIFY(
arr.value,
'$.Orders.Dest1',
JSON_VALUE(arr.value, '$.Customers.Source1')
),
'$.Customers.PurchasedQty',
JSON_VALUE(arr.value, '$.Customers.Qty')
),
','
) ']'
FROM OPENJSON(t.JsonData, '$.MultiOptions') arr
))
)
FROM jsontable t;
