8

I'm manipulating a JSON column in a SQL Azure table/database, the JSON object is formed like this:

{
  "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
    }
  ]
}

What I want to accomplish is to find a specific element inside the array "assignations" and then update some of its properties, just something like:

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

Of course this T-SQL is not working, I will appreciate any help on this

Anon Dev
  • 1,361
  • 3
  • 14
  • 29
  • This might be related to https://stackoverflow.com/questions/40538714/how-to-json-modify-on-array-of-array - a simplified version of that solution that only deals with array members (rather than members of an array-of-arrays) might work for you. – Ed Harper Dec 12 '16 at 13:50

2 Answers2

3

I've found a "simple workaround" to handle this, maybe it is not the best solution but I need a quick solution and this is working.

Basically I convert the array to a T-SQL Table, update the records on that table as desired, then convert that table to a JSON Array and with that array I replace the original one.

Sample code:

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
Anon Dev
  • 1,361
  • 3
  • 14
  • 29
2

We have to do something similar at work, and ended up with a similar approach to the one you ended up with, although we do the processing directly while reading the JSON, to avoid using a temp table or a table var.

  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

At the end this yields the same result.

D33
  • 291
  • 5
  • 11