SQL JSON 更新

SQL JSON update

如果我有这个JSON

{
      "hello1": "1",
      "hello2": "2"
}

我想从这个 JSON

更新它
{
      "hello2": "3"
}

我想要的结果是

{
      "hello1": "1",
      "hello2": "3"
}

有没有一种方法可以做到这一点而无需遍历 SQL 中的每个字段?

我目前的尝试是像这样手动更新每个值:

SET @OldJSON = JSON_MODIFY(
   @OldJSON,
   '$.hello1', 
   ISNULL(JSON_VALUE(@JSON,'$.hello1'), JSON_VALUE(@OldJSON,'$.hello1'))
)

获得预期结果的可能选项是:

  • JSON_MODIFY()SELECT 语句
  • JSON_MODIFY() 和动态语句

JSON_MODIFY()SELECT 语句:

documentation 中所述,在 SQL Server 2017 (14.x) 和 Azure SQL 数据库中,您可以提供变量(或表达式在这种情况下)作为路径的值。 因此,您可以轻松地为每个新 key/value 对构建路径。

DECLARE @old varchar(1000) = '{"hello1":"1","hello2":"2","hello3":"3"}'
DECLARE @new varchar(1000) = '{"hello2":"a","hello3":"b"}'

SELECT @old = JSON_MODIFY(
   @old,
   CONCAT('$."', n.[key], '"'),
   COALESCE(n.[value], o.[value])
)
FROM OPENJSON(@old) o
JOIN OPENJSON(@new) n ON n.[key] = o.[key]

JSON_MODIFY() 和动态语句:

场景几乎相同,但每次更新都在单独的语句中,动态生成:

DECLARE @old varchar(1000) = '{"hello1":"1","hello2":"2","hello3":"3"}'
DECLARE @new varchar(1000) = '{"hello2":"a","hello3":"b"}'

DECLARE @stm nvarchar(max)
SELECT @stm = STRING_AGG(
   CONCAT(
      'SELECT @old = JSON_MODIFY(@old, ''$."', n.[key], '"'', ''',
      COALESCE(n.[value], o.[value]), ''')'
   ),
   '; '
)   
FROM OPENJSON(@old) o
JOIN OPENJSON(@new) n ON n.[key] = o.[key]

DECLARE @err int
EXEC @err = sp_executesql @stm, N'@old varchar(1000) OUTPUT', @old OUTPUT
IF @err = 0 PRINT 'Success' ELSE PRINT 'Error'

结果:

两种方法 return 以下 JSON:

{"hello1":"1","hello2":"a","hello3":"b"}

添加新的 key\value 对:

如果新的 JSON 内容包含新的 key\value 对,只需使用 FULL JOIN:

DECLARE @old varchar(1000) = '{"hello1":"1","hello2":"2","hello3":"3"}'
DECLARE @new varchar(1000) = '{"hello2":"a","hello4":"b"}'

SELECT @old = JSON_MODIFY(
   @old,
   CONCAT('$."', n.[key], '"'),
   COALESCE(n.[value], o.[value])
)
FROM OPENJSON(@old) o
FULL JOIN OPENJSON(@new) n ON n.[key] = o.[key]