Изменение нескольких элементов массива JSON в SQL Server 2017 - PullRequest
1 голос
/ 05 мая 2020

У меня есть таблица SQL Server 2017 Orders, в которой есть первичный ключ OrderId и nvarchar(max) столбец Details. Этот столбец содержит строку json, которая представляет собой массив «элементов». Вот пример:

{ items[
{
    "id": 1,
    "isDeleted": false
},
{
    "id": 2,
    "isDeleted": false
},
{
    "id": 3,
    "isDeleted": false
},
{
    "id": 4,
    "isDeleted": false
}
] }

Я пытаюсь выяснить, есть ли способ иметь один (или несколько) операторов SQL, который позволит мне обновить один или несколько из isDeleted атрибуты в столбце Details этой таблицы, учитывая OrderId для записи в таблице, а также список идентификаторов в столбце Details для обновления.

Так, например, я бы хотелось бы обновить идентификаторы 2 и 3, чтобы они были истинными в строковой записи Details JSON для данного OrderId. Я знаю, что смогу сделать это через некоторое время l oop и используя json_modify, но мне интересно, есть ли более элегантное решение с некоторой комбинацией json_modify, json_query или openjson.

Заранее благодарим за любые предложения.

Ответы [ 3 ]

2 голосов
/ 07 мая 2020

Вы можете использовать один из следующих подходов:

  • Анализируйте Details JSON для каждой OrderId uisng OPENJSON() и явной схемы. Результатом является таблица со столбцами, определенными в предложении WITH. Обновите эту таблицу и верните измененные данные как JSON снова, используя FOR JSON.
  • Разберите Details JSON для каждой OrderId uisng OPENJSON() и схемы по умолчанию. Результатом является таблица со столбцами key, value и type и по одной строке для каждого элемента (JSON объект) в массиве items JSON. Обновите эту таблицу и сгенерируйте массив items JSON с использованием строкового подхода (я не думаю, что FOR JSON может генерировать массив скалярных значений / JSON объектов). Обновите JSON в исходной таблице с помощью JSON_MODIFY().
  • Сгенерируйте и выполните инструкцию Dynami c, используя JSON_MODIFY()

Таблица с данными:

CREATE TABLE Orders (OrderId int, Details nvarchar(max))
INSERT INTO Orders (OrderId, Details)
VALUES 
   (1, N'{"items":[{"id":1,"isDeleted":false},{"id":2,"isDeleted":false},{"id":3,"isDeleted":false},{"id":4,"isDeleted":false}]}'),
   (2, N'{"items":[{"id":11,"isDeleted":false},{"id":12,"isDeleted":false},{"id":13,"isDeleted":false}]}')

Таблица с идентификаторами:

CREATE TABLE ItemIds (id int)
INSERT INTO ItemIds (id) VALUES (1), (3)

Оператор с OPENJSON() и явной схемой:

UPDATE Orders
SET Details = (
   SELECT 
      j.id AS id, 
      CONVERT(bit, CASE WHEN i.id IS NOT NULL THEN 1 ELSE j.isDeleted END) AS isDeleted
   FROM OPENJSON(Details, '$.items') WITH (
      id int '$.id', 
      isDeleted bit '$.isDeleted'
   ) j
   LEFT OUTER JOIN ItemIds i ON j.id = i.id
   FOR JSON AUTO, ROOT('Items')
)
WHERE OrderId = 1

Оператор с OPENJSON() и схемой по умолчанию:

UPDATE Orders
SET Details = JSON_MODIFY(
   Details,
   '$.items',
   JSON_QUERY((
      SELECT CONCAT(
         '[', 
         STRING_AGG(
            CASE 
               WHEN i.id IS NULL THEN j.[value] 
               ELSE JSON_MODIFY(j.[value], '$.isDeleted', CONVERT(bit, 1)) 
            END,
            ','
         ),
         ']'
      )   
      FROM OPENJSON(Details, '$.items') j
      LEFT OUTER JOIN ItemIds i ON CONVERT(int, JSON_VALUE(j.[value], '$.id')) = i.id
   ))
)
WHERE OrderId = 1

Dynami c выписка:

DECLARE @stm nvarchar(max) 
SELECT @stm = STRING_AGG(
    CONCAT(
      'UPDATE Orders ',
      'SET Details = JSON_MODIFY(Details, ''$.items[', a.[key], '].isDeleted'', CONVERT(bit, 1)) ',
      'WHERE OrderId = ', o.OrderId, ';'
   ),
   ' '
)   
FROM Orders o
CROSS APPLY (
   SELECT o.OrderId, j1.[key]
   FROM OPENJSON(o.Details, '$.items') j1
   CROSS APPLY OPENJSON(j1.[value]) WITH (id int '$.id') j2
   WHERE j2.id IN (SELECT id FROM ItemIds)
) a   
WHERE o.OrderId = 1

PRINT @stm 
EXEC sp_executesql @stm

Результат:

OrderId Details
1   {"items":[{"id":1,"isDeleted":true},{"id":2,"isDeleted":false},{"id":3,"isDeleted":true},{"id":4,"isDeleted":false}]}
2   {"items":[{"id":11,"isDeleted":false},{"id":12,"isDeleted":false},{"id":13,"isDeleted":false}]}
0 голосов
/ 06 мая 2020

У меня нет нужной версии SQL Server для тестирования этого кода. Но вы должны иметь возможность запрашивать и изменять данные и генерировать новую строку json.

DECLARE @json nvarchar(max) = '{"items" : [{"id": 1, "isDeleted": false}, {"id": 2, "isDeleted": false}, {"id": 3, "isDeleted": false}, {"id": 4, "isDeleted": false}]}'

SELECT *
  FROM OPENJSON(@json)
  WITH (id int '$.items.id', isDeleted bit '$.items.isDeleted')
0 голосов
/ 05 мая 2020

SQL Сервер прекрасно справляется с такой операцией. Это другой вопрос, если это хороший дизайн. db <> fiddle demo

Как это работает:

  1. Разобрать JSON в табличный формат

  2. Выполнение манипуляций с данными (здесь используется @t в качестве параметра)

  3. Агрегировать обратно в JSON

  4. Выполнить ОБНОВЛЕНИЕ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...