2016-11-10 6 views
2

私strucutreは、私は何をしたいのは、これを行うことです。この配列の配列でJSON_MODIFYを使用する方法は?

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' 
) 

答えて

3

これは、希望するほど簡単ではありません。私は、JSON構造内のアイテムの完全なパスを照会する簡単な方法がないように思われることに驚いていました。

JSON_MODIFYは、配列のメンバをターゲットにするときにのみ配列の表示を受け付けることができるため、ここでの作業の多くは各入れ子配列のインデックスを生成します。 [key]列は、OPENJSONWITH句なしで使用する場合にのみ生成されるため、クエリを再利用できませんでした。

さらに、JSON_MODIFYは、JSONパスの文字列リテラルのみを受け入れるため、動的SQLを使用して更新を実行する必要があります。

(このソリューションは、あなたが例えば'Render1'特定RenderName更新することを想定していますのでご注意ください - 。質問は、この時点では不明であるが)

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 
+0

非常にきちんとしたソリューション。私は受け入れますが、残念ながらこのプロジェクトでは、何かを更新する必要があるたびにJSON全体を書き直すことにしました。 – Bill

関連する問題