如何更新json对象中数组的特定项

时间:2016-12-12 12:44:28

标签: tsql azure-sql-database sql-server-2016

我正在操作SQL Azure表/数据库中的JSON列,JSON对象形成如下:

{
  "statusId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
  "creationDateTime": "",
  "assignations": [
    {
      "userId": "CA3B0589-B558-4FCC-93A6-560754D324FC",
      "dateTime": "",
      "isCurrentAssigned": false
    },
    {
      "userId": "CA3B0589-B558-4FCC-93A6-560754D325E8",
      "dateTime": "",
      "isCurrentAssigned": false
    },
    {
      "userId": "CA3B0589-B558-4FCC-93A6-560754D347N",
      "dateTime": "",
      "isCurrentAssigned": true
    }
  ]
}

我想要完成的是在数组“assignations”中找到一个特定元素,然后更新它的一些属性,例如:

UPDATE MyTable
SET JsonData = JSON_MODIFY(JsonData, '$.assignations.isCurrentAssigned', CONVERT(BIT, 0))
FROM MyDb
WHERE JSON_VALUE(JsonData, '$.assignations.isCurrentAssigned') = CONVERT(BIT, 1) AND
JSON_VALUE(JsonData, '$.assignations.userId') =  CONVERT(UNIQUEIDENTIFIER, 'CA3B0589-B558-4FCC-93A6-560754D347N')

当然这个T-SQL无法正常工作,我将不胜感激为您提供帮助

2 个答案:

答案 0 :(得分:1)

我找到了一个简单的解决方法"为了解决这个问题,也许这不是最好的解决方案,但我需要一个快速的解决方案,这是有效的。

基本上我将数组转换为T-SQL表,根据需要更新该表上的记录,然后将该表转换为JSON数组,并使用该数组替换原来的数据。

示例代码:

DECLARE @SomeJSON NVARCHAR(MAX) = 
'{
  "statusId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
  "creationDateTime": "abc",
  "assignations": [
    {
      "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
      "creationDateTime": "",
      "isCurrentAssigned": false
    },
    {
      "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
      "creationDateTime": "",
      "isCurrentAssigned": false
    },
    {
      "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
      "creationDateTime": "",
      "isCurrentAssigned": true
    }
  ]
}'


DECLARE @TblAssignations TABLE
(
userId UNIQUEIDENTIFIER NULL,
creationDateTime DATETIME NULL,
isCurrentAssigned BIT NULL
)

INSERT INTO @TblAssignations
SELECT *
FROM OPENJSON(@SomeJSON, '$.assignations')
WITH(userId UNIQUEIDENTIFIER, creationDateTime DATETIME, isCurrentAssigned BIT)

UPDATE @TblAssignations
SET isCurrentAssigned = 0
WHERE userId = '5A5BC717-F33A-42A5-8E48-99531C30EC87' AND
isCurrentAssigned = 1

INSERT INTO @TblAssignations
VALUES
(
'5A5BC717-F33A-42A5-8E48-99531C30EC87',
'',
1
)

DECLARE @NewParentAssignations NVARCHAR(MAX) = (SELECT * FROM @TblAssignations FOR JSON PATH)

SET @SomeJSON = JSON_MODIFY(@SomeJSON, '$.assignations', JSON_QUERY(@NewParentAssignations))

SELECT @SomeJSON

答案 1 :(得分:1)

我们必须在工作中做类似的事情,并最终采用与您最终完成的方法类似的方法,尽管我们在读取JSON时直接进行处理,以避免使用临时表或表变量。< / p>

  DECLARE @SomeJSON NVARCHAR(MAX) = 
    '{
      "statusId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
      "creationDateTime": "abc",
      "assignations": [
        {
          "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
          "creationDateTime": "",
          "isCurrentAssigned": false
        },
        {
          "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
          "creationDateTime": "",
          "isCurrentAssigned": false
        },
        {
          "userId": "5A5BC717-F33A-42A5-8E48-99531C30EC87",
          "creationDateTime": "",
          "isCurrentAssigned": true
        }
      ]
    }'

    DECLARE @NewParentAssignations NVARCHAR(MAX) = (
        SELECT * 
        FROM (

            SELECT --the update is done with the CASE clause
                userId, 
                creationDateTime,
                CASE WHEN userId = '5A5BC717-F33A-42A5-8E48-99531C30EC87' AND isCurrentAssigned = 1
                     THEN CAST (0 AS BIT)
                     ELSE isCurrentAssigned
                END AS isCurrentAssigned
            FROM OPENJSON(@SomeJSON, '$.assignations')
            WITH(userId UNIQUEIDENTIFIER, creationDateTime DATETIME, isCurrentAssigned BIT)

            UNION ALL -- the insert is done using UNION ALL

            SELECT '5A5BC717-F33A-42A5-8E48-99531C30EC87' AS userId, '' AS creationDateTime, CAST (1 AS BIT) AS isCurrentAssigned 

        ) Result
        FOR JSON PATH
    )


    SET @SomeJSON = JSON_MODIFY(@SomeJSON, '$.assignations', JSON_QUERY(@NewParentAssignations))

    SELECT @SomeJSON

最后会产生相同的结果。