2016-11-10 2 views
2

Mein strucutre aussehen wie diesWie JSON_MODIFY auf 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" 
          } 
         ] 
        } 
       ] 
      } 
     ] 
    } 
' 

Was Ich mag würde, ist zu tun, dies zu tun:

update FieldData = 'DataUpdated' 
where FieldName = 'Field2' 
and RenderName = 'Render' 
and SectionName = 'Section1' 

Wie würde ich dies mit JSON_MODIFY tun?

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

Antwort

3

Dies ist nicht so einfach, wie man hoffen könnte. Ich war überrascht, dass es anscheinend keine einfache Möglichkeit gibt, den vollständigen Pfad eines Elements in einer JSON-Struktur abzufragen.

JSON_MODIFY können Array-Indices nur dann akzeptieren, wenn sie auf ein Mitglied eines Arrays ausgerichtet sind. Daher wird hier die meiste Arbeit für die Generierung der Indizes für jedes verschachtelte Array-Element benötigt. Es scheint, dass die Spalte [key] nur generiert werden kann, wenn OPENJSON ohne eine WITH-Klausel verwendet wird, sodass ich Ihre Abfrage nicht erneut verwenden kann.

Außerdem akzeptiert JSON_MODIFY nur ein Zeichenfolgenliteral für den JSON-Pfad, daher muss das Update mit dynamischem SQL durchgeführt werden.

(Bitte beachten Sie, dass diese Lösung setzt voraus, dass Sie eine bestimmte RenderName z 'Render1' aktualisieren wollen -. Die Frage in diesem Punkt unklar ist)

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

Sehr saubere Lösung. Ich werde akzeptieren, aber leider für das Projekt haben wir beschlossen, den gesamten JSON einfach jedes Mal neu zu schreiben, wenn etwas aktualisiert werden muss. – Bill