Array of Array 如何 JSON_MODIFY?
How to JSON_MODIFY on Array of Array?
我的结构是这样的
Declare @layout NVARCHAR(MAX) = N'
{
"Sections": [
{
"SectionName":"Section1",
"SectionOrder":1,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
},
{
"SectionName":"Section2",
"SectionOrder":2,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
}
]
}
'
我想做的是这样做:
update FieldData = 'DataUpdated'
where FieldName = 'Field2'
and RenderName = 'Render'
and SectionName = 'Section1'
我如何使用 JSON_MODIFY 执行此操作?
I can GET the data using the following query:
SELECT SectionName, SectionOrder, RenderName, RenderOrder, FieldName, FieldData FROM (
SELECT SectionName, SectionOrder, RenderName, RenderOrder, Fields FROM (
select SectionName, SectionOrder, Renders
from OPENJSON(@layout,'$.Sections')
WITH (
SectionName nvarchar(MAX) '$.SectionName',
SectionOrder nvarchar(MAX) '$.SectionOrder',
Renders nvarchar(MAX) '$.Renders' as JSON
)
) as Sections
CROSS APPLY OPENJSON(Renders,'$')
WITH (
RenderName nvarchar(MAX) '$.RenderName',
RenderOrder nvarchar(MAX) '$.RenderOrder',
Fields nvarchar(MAX) '$.Fields' as JSON
)
) as Renders
CROSS APPLY OPENJSON(Fields,'$')
WITH (
FieldName nvarchar(MAX) '$.FieldName',
FieldData nvarchar(MAX) '$.FieldData'
)
这并不像人们希望的那么简单。我很惊讶似乎没有简单的方法来查询 JSON 结构中项目的完整路径。
JSON_MODIFY
只能在以数组成员为目标时接受数组索引,因此这里的大部分工作都是为每个嵌套数组成员生成索引。似乎 [key]
列只能在不使用 WITH
子句的情况下使用 OPENJSON
时生成,因此我无法重用您的查询。
此外,JSON_MODIFY
将只接受 JSON 路径的字符串文字,因此必须使用动态 SQL.
进行更新
(请注意,此解决方案假定您要更新特定的 RenderName,例如 'Render1'
- 在这一点上问题尚不清楚。)
DECLARE @path nvarchar(2048)
SELECT @path = FORMATMESSAGE('SET @layout = JSON_MODIFY(@layout, ''$.Sections[%s].Renders[%s].Fields[%s].FieldData'', @newValue)' ,sectionindex, renderindex, [key])
FROM
(
SELECT sectionindex, sectionName, b.[key] as renderindex, b.[value] AS bvalue, JSON_VALUE([Value], '$.RenderName') AS renderName
FROM
(SELECT [key] AS sectionindex, [Value] AS avalue, JSON_VALUE([Value], '$.SectionName') AS sectionName
FROM OPENJSON(@layout, '$.Sections') ) AS sections
CROSS APPLY OPENJSON(sections.avalue, '$.Renders') AS b
) AS renders
CROSS APPLY OPENJSON(renders.bvalue,'$.Fields'
) AS d
WHERE JSON_VALUE([Value], '$.FieldName') = 'Field2'
AND RenderName = 'Render1'
AND SectionName = 'Section1'
-- execute the update; this has to happen in dynamic SQL because the JSON_MODIFY path has to be a literal value, and cannot be a variable
EXEC sp_executeSQL @path, N'@layout nvarchar(max) OUTPUT, @newValue nvarchar(max)', @layout = @layout OUTPUT, @newValue = 'DateUpdated'
--check the results
SELECT sectionindex, sectionName, renderindex, rendername, [key] AS fieldindex, JSON_VALUE([Value], '$.FieldName') AS FieldName, JSON_VALUE([Value], '$.FieldData') AS FieldName
FROM
(
SELECT sectionindex, sectionName, b.[key] AS renderindex, b.[value] AS bvalue, JSON_VALUE([Value], '$.RenderName') AS renderName
FROM
(SELECT [key] as sectionindex, [Value] as avalue, JSON_VALUE([Value], '$.SectionName') AS sectionName
FROM OPENJSON(@layout, '$.Sections') ) AS sections
CROSS APPLY OPENJSON(sections.avalue, '$.Renders') AS b
) AS renders
CROSS APPLY OPENJSON(renders.bvalue,'$.Fields'
) AS d
您可以使用不带 WITH
的 CROSS APPLY
来获得数组中的 key
位置。
执行以下过程以查看更新后的 JSON:execute TesteJSON
CREATE PROCEDURE TesteJSON
AS
BEGIN
DECLARE @layout NVARCHAR(MAX) = N'
{
"Sections": [
{
"SectionName":"Section1",
"SectionOrder":1,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
},
{
"SectionName":"Section2",
"SectionOrder":2,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
}
]
}
';
DECLARE @TestTbl TABLE ( jsonObj VARCHAR(MAX) );
INSERT INTO @TestTbl ( jsonObj ) VALUES ( @layout );
-- Test the current data by uncommenting
-- SELECT * FROM @TestTbl;
WITH cte AS (
SELECT Sections.[key] as k1, Renders.[key] as k2, Fields.[key] as k3, jsonObj FROM @TestTbl as tt
CROSS APPLY OPENJSON(jsonObj, '$.Sections') Sections
CROSS APPLY OPENJSON(Sections.value, '$.Renders' ) AS Renders
CROSS APPLY OPENJSON(Renders.value, '$.Fields' ) AS Fields
WHERE
JSON_VALUE(Sections.value, '$.SectionName') = 'Section1'
AND JSON_VALUE(Renders.value, '$.RenderName') = 'Render1'
AND JSON_VALUE(Fields.value, '$.FieldName') = 'Field2'
)
UPDATE cte SET jsonObj = JSON_MODIFY(jsonObj, '$.Sections[' + k1 + '].Renders[' + k2 + '].Fields[' + k3 + '].FieldData', 'DataUpdated')
SELECT * FROM @TestTbl;
END
我的结构是这样的
Declare @layout NVARCHAR(MAX) = N'
{
"Sections": [
{
"SectionName":"Section1",
"SectionOrder":1,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
},
{
"SectionName":"Section2",
"SectionOrder":2,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
}
]
}
'
我想做的是这样做:
update FieldData = 'DataUpdated'
where FieldName = 'Field2'
and RenderName = 'Render'
and SectionName = 'Section1'
我如何使用 JSON_MODIFY 执行此操作?
I can GET the data using the following query:
SELECT SectionName, SectionOrder, RenderName, RenderOrder, FieldName, FieldData FROM (
SELECT SectionName, SectionOrder, RenderName, RenderOrder, Fields FROM (
select SectionName, SectionOrder, Renders
from OPENJSON(@layout,'$.Sections')
WITH (
SectionName nvarchar(MAX) '$.SectionName',
SectionOrder nvarchar(MAX) '$.SectionOrder',
Renders nvarchar(MAX) '$.Renders' as JSON
)
) as Sections
CROSS APPLY OPENJSON(Renders,'$')
WITH (
RenderName nvarchar(MAX) '$.RenderName',
RenderOrder nvarchar(MAX) '$.RenderOrder',
Fields nvarchar(MAX) '$.Fields' as JSON
)
) as Renders
CROSS APPLY OPENJSON(Fields,'$')
WITH (
FieldName nvarchar(MAX) '$.FieldName',
FieldData nvarchar(MAX) '$.FieldData'
)
这并不像人们希望的那么简单。我很惊讶似乎没有简单的方法来查询 JSON 结构中项目的完整路径。
JSON_MODIFY
只能在以数组成员为目标时接受数组索引,因此这里的大部分工作都是为每个嵌套数组成员生成索引。似乎 [key]
列只能在不使用 WITH
子句的情况下使用 OPENJSON
时生成,因此我无法重用您的查询。
此外,JSON_MODIFY
将只接受 JSON 路径的字符串文字,因此必须使用动态 SQL.
(请注意,此解决方案假定您要更新特定的 RenderName,例如 'Render1'
- 在这一点上问题尚不清楚。)
DECLARE @path nvarchar(2048)
SELECT @path = FORMATMESSAGE('SET @layout = JSON_MODIFY(@layout, ''$.Sections[%s].Renders[%s].Fields[%s].FieldData'', @newValue)' ,sectionindex, renderindex, [key])
FROM
(
SELECT sectionindex, sectionName, b.[key] as renderindex, b.[value] AS bvalue, JSON_VALUE([Value], '$.RenderName') AS renderName
FROM
(SELECT [key] AS sectionindex, [Value] AS avalue, JSON_VALUE([Value], '$.SectionName') AS sectionName
FROM OPENJSON(@layout, '$.Sections') ) AS sections
CROSS APPLY OPENJSON(sections.avalue, '$.Renders') AS b
) AS renders
CROSS APPLY OPENJSON(renders.bvalue,'$.Fields'
) AS d
WHERE JSON_VALUE([Value], '$.FieldName') = 'Field2'
AND RenderName = 'Render1'
AND SectionName = 'Section1'
-- execute the update; this has to happen in dynamic SQL because the JSON_MODIFY path has to be a literal value, and cannot be a variable
EXEC sp_executeSQL @path, N'@layout nvarchar(max) OUTPUT, @newValue nvarchar(max)', @layout = @layout OUTPUT, @newValue = 'DateUpdated'
--check the results
SELECT sectionindex, sectionName, renderindex, rendername, [key] AS fieldindex, JSON_VALUE([Value], '$.FieldName') AS FieldName, JSON_VALUE([Value], '$.FieldData') AS FieldName
FROM
(
SELECT sectionindex, sectionName, b.[key] AS renderindex, b.[value] AS bvalue, JSON_VALUE([Value], '$.RenderName') AS renderName
FROM
(SELECT [key] as sectionindex, [Value] as avalue, JSON_VALUE([Value], '$.SectionName') AS sectionName
FROM OPENJSON(@layout, '$.Sections') ) AS sections
CROSS APPLY OPENJSON(sections.avalue, '$.Renders') AS b
) AS renders
CROSS APPLY OPENJSON(renders.bvalue,'$.Fields'
) AS d
您可以使用不带 WITH
的 CROSS APPLY
来获得数组中的 key
位置。
执行以下过程以查看更新后的 JSON:execute TesteJSON
CREATE PROCEDURE TesteJSON
AS
BEGIN
DECLARE @layout NVARCHAR(MAX) = N'
{
"Sections": [
{
"SectionName":"Section1",
"SectionOrder":1,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
},
{
"SectionName":"Section2",
"SectionOrder":2,
"Renders":[
{
"RenderName":"Render1",
"RenderOrder":1,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
}
]
},
{
"RenderName":"Render2",
"RenderOrder":2,
"Fields":[
{
"FieldName":"Field1",
"FieldData":"Data1"
},
{
"FieldName":"Field2",
"FieldData":"Data2"
}
]
}
]
}
]
}
';
DECLARE @TestTbl TABLE ( jsonObj VARCHAR(MAX) );
INSERT INTO @TestTbl ( jsonObj ) VALUES ( @layout );
-- Test the current data by uncommenting
-- SELECT * FROM @TestTbl;
WITH cte AS (
SELECT Sections.[key] as k1, Renders.[key] as k2, Fields.[key] as k3, jsonObj FROM @TestTbl as tt
CROSS APPLY OPENJSON(jsonObj, '$.Sections') Sections
CROSS APPLY OPENJSON(Sections.value, '$.Renders' ) AS Renders
CROSS APPLY OPENJSON(Renders.value, '$.Fields' ) AS Fields
WHERE
JSON_VALUE(Sections.value, '$.SectionName') = 'Section1'
AND JSON_VALUE(Renders.value, '$.RenderName') = 'Render1'
AND JSON_VALUE(Fields.value, '$.FieldName') = 'Field2'
)
UPDATE cte SET jsonObj = JSON_MODIFY(jsonObj, '$.Sections[' + k1 + '].Renders[' + k2 + '].Fields[' + k3 + '].FieldData', 'DataUpdated')
SELECT * FROM @TestTbl;
END