Удалите известное подмножество узлов из JSON в SQLAzure - PullRequest
0 голосов
/ 07 сентября 2018

Когда-то существовала одна строка данных (значительно упрощенная, фактические данные json составляют 10 КБ +), таким образом:

ID, json
1, '{
      "a1.arr": [1,2,3],
      "a1.boo": true,
      "a1.str": "hello",
      "a1.num": 123
    }'

Процесс должен был написать еще одну запись с преимущественно другими данными:

ID, json
2, '{
      "a1.arr": [1,2,3], //from ID 1
      "a2.arr": [4,5,6], //new (and so are all below)
      "a2.boo": false,
      "a2.str": "goodbye",
      "a2.num": 456
    }'

Но из-за какой-то внешней ошибки исходный набор json из идентификатора 1 также оказался представлен в идентификаторе 2, поэтому теперь таблица выглядит так:

ID, json
1, '{
      "a1.arr": [1,2,3],
      "a1.boo": true,
      "a1.str": "hello",
      "a1.num": 123
    }'
2, '{
      "a1.arr": [1,2,3],
      "a1.boo": true,    //extraneous
      "a1.str": "hello", //extraneous
      "a1.num": 123,     //extraneous
      "a2.arr": [4,5,6],
      "a2.boo": false,
      "a2.str": "goodbye",
      "a2.num": 456
    }'

Я хотел бы знать, есть ли способ удалить посторонние строки из записи ID 2.

Я считаю, что вся строка JSON из ID 1 представлена ​​в ID 2 как непрерывный блок, поэтому замена строки может сработать, но есть вероятность, что произошло некоторое переупорядочение. Немного запутался с элементом, который должен остаться, хотя

Существует также вероятность того, что некоторые значения узлов a1. * Были немного изменены (я не делал различий), но я рад использовать только имена узлов, а не их значения, при оценке того, узел должен быть удален. Один из узлов (a1.arr) должен храниться в ID 2. Следовательно, набор результатов должен выглядеть следующим образом:

ID, json
1, '{
      "a1.arr": [1,2,3],
      "a1.boo": true,
      "a1.str": "hello",
      "a1.num": 123
    }'
2, '{
      "a1.arr": [1,2,3],
      "a2.arr": [4,5,6],
      "a2.boo": false,
      "a2.str": "goodbye",
      "a2.num": 456
    }'

Я начал играть с https://dba.stackexchange.com/questions/168303/can-sql-server-2016-extract-node-names-from-json, чтобы получить список имен узлов из идентификатора 1, который я хочу удалить из идентификатора 2, но я не уверен, как мне затем удалить их из JSON идентификатора 2 - предположительно последовательность десериализации, редукции и повторной сериализации?

1 Ответ

0 голосов
/ 11 сентября 2018

Вы можете придерживаться этого подхода:

  1. получить ключи, которые вы хотите заменить на openjson в строке со значением id=1
  2. используйте cross apply для фильтрации ключей в строках с id>1
  3. восстановить строку json без ненужных ключей, используя STRING_AGG и group by

Этот код должен работать:

declare @tmp table ([id] int, jsonValue nvarchar(max))
declare @source_json nvarchar(max)

insert into @tmp values
 (1, '{"a1.arr":[1,2,3],"a1.boo":true,"a1.str":"hello","a1.num":123}')
,(2, '{"a1.arr":[1,2,3],"a1.boo":true,"a1.str":"hello","a1.num":123,"a2.arr":[4,5,6],"a2.boo":false,"a2.str":"goodbye","a2.num":456}')
,(3, '{"a1.arr":[1,2,3],"a1.boo":true,"a1.str":"hello","a1.num":123,"a3.arr":[4,5,6],"a3.boo":false,"a3.str":"goodbye","a3.num":456}')

--get json string from id=1
select @source_json = jsonValue from @tmp where [id] = 1

--rebuild json string for id > 1 removing keys from id = 1
select t.[id],   
       '{' + STRING_AGG( '"' + g.[key] + '":"' + STRING_ESCAPE(g.[value], 'json')  + '"', ',') + '}' as [json]
from @tmp t cross apply openjson(jsonValue) g
where t.id > 1
    and g.[key] not in (select [key] from openjson(@source_json) where [key] <> 'a1.arr')
group by t.id

Результат:

enter image description here

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