【问题标题】:SQL JSON updateSQL JSON 更新
【发布时间】:2020-12-01 07:48:00
【问题描述】:

如果我有这个 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'))
)

【问题讨论】:

  • 它的 MS SQL Server
  • @Hasan ...without the need to go through every field... 是什么意思?
  • 请向我们展示您的尝试 - SO 不是代码编写服务。
  • 我什么都没尝试,我打算像这样手动更新每个值,SET @OldJSON = JSON_MODIFY(@OldJSON,'$.hello1', ISNULL(JSON_VALUE(@JSON,'$.hello1'), JSON_VALUE(@OldJSON,'$.hello1'))),但我希望找到某种动态方式,我只会说SET @OldJSON = SomeKindOfMethodHere(@JSON)
  • @Hasan 新的 JSON 是否总是包含一对 key\value 以及您的 SQL Server 版本是多少?

标签: sql json sql-server sql-server-2019


【解决方案1】:

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

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

结果:

两种方法都返回以下 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]

【讨论】:

  • 这正是我所需要的,但它缺少一件事,即如果我在新 JSON 中有一个新字段,它将不会执行到旧的字段,就像假设我有“hello4”在新的 JSON 中,如果我运行它,OldJSON 将被更新,但不会添加“hello4”字段。但这很好,很有帮助,非常感谢
  • @Hasan 使用FULL JOIN。答案已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多