JSON_MODIFY按索引在json数组中插入值

时间:2018-04-12 18:39:43

标签: json sql-server tsql

索引是否在json数组中有任何插入或更新值。 我有一个包含这些值的列:

["qwe","123"]

我希望在中间插入新值:

["qwe","asd","123"]

或删除一个:

["123"]

如何使用JSON_MODIFY完成?

我只设法附加最后一个值:

select JSON_MODIFY([Column], 'append $', '')
from MyTable

或更新将中间值更改为null:

select JSON_MODIFY([Column], '$[1]', NULL)
from MyTable

然后将其更换为空。

2 个答案:

答案 0 :(得分:2)

如果要在最后一个值之前插入新值,可以将最后一个值再次追加为n+1,然后替换n值:

DECLARE @Data TABLE
(
     [ID] INT
    ,[Column]  NVARCHAR(MAX)
);

INSERT INTO @Data ([ID], [Column])
VALUES (1, '["qwe","123"]');


SELECT JSON_MODIFY(JSON_MODIFY([Column], 'append $', JSON_VALUE([Column], '$[1]')), '$[1]', 'asd')
FROM @Data
WHERE [ID] = 1;

enter image description here

现在,如果我们有很多元素,并且如果我们想在第二个或第三个索引上插入新元素,上面的代码将不起作用,因为我们需要在新的元素之后交换所有值。

为此,我们可以使用OPNEJSON函数拆分值,然后使用适当的索引插入新值,并使用FOR XMLSRING AGGREGATE函数连接值。

DECLARE @Data TABLE
(
     [ID] INT
    ,[Column]  NVARCHAR(MAX)
);

INSERT INTO @Data ([ID], [Column])
VALUES (2, '["qwe","123", "125" ,"126"]');

SELECT 
'[' + 
STUFF
(
    (
        SELECT ',' + [value] AS [value]
        FROM
        (
            SELECT JS.[value]
                  ,JS.[key] * 1.0
            FROM @Data DS
            CROSS APPLY OPENJSON([Column]) JS
            WHERE DS.[ID] = 2
            UNION ALL
            SELECT 'asd'
                  ,0.1
        ) DS ([value], [key])
        ORDER BY [key]
        FOR XML PATH, TYPE
    ).value('.', 'NVARCHAR(MAX)')
    ,1
    ,1
    ,''
)
+']';

enter image description here

答案 1 :(得分:1)

我认为没有正常的做法。

我发现只有以下方法如何做到

-- create and fill #TestData
SELECT '["qwe","asd","123"]' json_str
INTO #TestData
UNION ALL
SELECT '["zxc","asd","321"]'
UNION ALL
SELECT '[]'
UNION ALL
SELECT '["qwe","asd","12\"3"]' -- escaped quotes
UNION ALL
SELECT '["qwe","asd","<123>"]' -- special characters

-- delete demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',STUFF((
      SELECT CONCAT(',"',REPLACE([value],'"','\"'),'"')
      FROM OPENJSON(json_str, '$')
      WHERE [key]<>1 -- exclude element with index 1
      ORDER BY [key]
      FOR XML PATH('')),1,1,''),']')) new_json_str
FROM #TestData

-- insert demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',STUFF((
      SELECT CONCAT(',"',REPLACE([value],'"','\"'),'"')
      FROM
        (
          SELECT 1 RowPriority,[key],[value]
          FROM OPENJSON(json_str, '$')

          UNION ALL

          SELECT
            2 RowPriority,
            0, -- add after key with index 0
            'new value' -- value
          ) q
      ORDER BY [key],RowPriority -- sort values
      FOR XML PATH('')),1,1,''),']')) new_json_str
FROM #TestData

DROP TABLE #TestData

还有一个例子,用于删除另一个条件的值并插入多个值

-- create and fill #TestData
SELECT '["qwe","asd","123"]' json_str
INTO #TestData
UNION ALL
SELECT '["zxc","asd","321"]'
UNION ALL
SELECT '[]' -- empty array
UNION ALL
SELECT '["qwe","asd","12\"3"]' -- escaped quotes
UNION ALL
SELECT '["qwe","asd","<123>"]' -- special characters

-- delete with another condition demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',STUFF((
      SELECT CONCAT(',"',REPLACE([value],'"','\"'),'"')
      FROM OPENJSON(json_str, '$')
      WHERE [value] NOT IN('qwe','123') -- another delete condition
      ORDER BY [key]
      FOR XML PATH('')),1,1,''),']')) new_json_str
FROM #TestData

-- insert several values demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',STUFF((
      SELECT CONCAT(',"',REPLACE([value],'"','\"'),'"')
      FROM
        (
          SELECT 1 RowPriority,0 NewValOrder,[key],[value]
          FROM OPENJSON(json_str, '$')

          UNION ALL

          SELECT 2 RowPriority,NewValOrder,AfterPosition,[value]
          FROM (VALUES(0,1,'new value 1'),(0,2,'new value 2')) v(AfterPosition,NewValOrder,[value])
          ) q
      ORDER BY [key],RowPriority,NewValOrder -- sort values
      FOR XML PATH('')),1,1,''),']')) new_json_str
FROM #TestData

DROP TABLE #TestData

希望这个变体适合你。

STRING_AGG代替FOR XML PATH('')

的变体
-- create and fill #TestData
SELECT '["qwe","asd","123"]' json_str
INTO #TestData
UNION ALL
SELECT '["zxc","asd","321"]'
UNION ALL
SELECT '[]' -- empty array
UNION ALL
SELECT '["qwe","asd","12\"3"]' -- escaped quotes
UNION ALL
SELECT '["qwe","asd","<123>"]' -- special characters

-- delete with another condition demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',
        (
          SELECT STRING_AGG(CONCAT('"',REPLACE([value],'"','\"'),'"'),',') WITHIN GROUP(ORDER BY [key])
          FROM OPENJSON(json_str, '$')
          WHERE [value] NOT IN('qwe','123') -- another delete condition
        ),']')) new_json_str
FROM #TestData

-- insert several values demo
SELECT
  json_str,
  JSON_QUERY(CONCAT('[',
        (
          SELECT STRING_AGG(CONCAT('"',REPLACE([value],'"','\"'),'"'),',') WITHIN GROUP(ORDER BY [key],RowPriority,NewValOrder)
          FROM
            (
              SELECT 1 RowPriority,0 NewValOrder,[key],[value]
              FROM OPENJSON(json_str, '$')

              UNION ALL

              SELECT 2 RowPriority,NewValOrder,AfterPosition,[value]
              FROM (VALUES(0,1,'new value 1'),(0,2,'new value 2')) v(AfterPosition,NewValOrder,[value])
              ) q
         ),']')) new_json_str
FROM #TestData

DROP TABLE #TestData

也许最后一个变体会更好,因为构造FOR XML PATH('')会替换一些特殊字符(例如:< - &lt;)。