JSON_MODIFY 没有循环的所有值

JSON_MODIFY all values without looping

参见下面的示例。我如何使用 JSON_MODIFY 或其他方式将所有“disc”值修改为“100”,而不必循环更新每个数组项?

create table #temp_data (json_text nvarchar(max))
insert into #temp_data select 
'
   "curr":"USD",
   "items":[
      {
         "line":1,
         "disc":10,
      },
      {
         "line":2,
         "disc":11
      },
      {
         "line":3,
         "disc":12,
      }
   ]
}'
select * from #temp_data

一种方法是使用传统的 SQL DML UPDATE 将 json_text 替换为从现有的 JSON 派生的新片段。像这样

如果需要,可以添加

JSON_MODIFY。

drop table if exists #temp_data;
go
create table #temp_data (json_text nvarchar(max));

insert into #temp_data(json_text) values( 
N'{
   "curr":"USD",
   "items":[
      {
         "line":1,
         "disc":10
      },
      {
         "line":2,
         "disc":11
      },
      {
         "line":3,
         "disc":12
      }
   ]
}');

update #temp_data
set json_text=( select json_value(d.json_text, N'strict $.curr') curr, 
                       (select j2.line, j2.disc+100 as disc
                        from #temp_data td
                        cross apply openjson(td.json_text) 
                                     with(curr       nvarchar(20),
                                          items      nvarchar(max) as json) j1
                     cross apply openjson(j1.items)
                                     with(line       int,
                                          disc       int) j2
                        for json path) items
                from #temp_data d
                for json path, without_array_wrapper);

select * from #temp_data;
{
  "curr": "USD",
  "items": [
    {
      "line": 1,
      "disc": 210
    },
    {
      "line": 2,
      "disc": 211
    },
    {
      "line": 3,
      "disc": 212
    }
  ]
}

无法在 JSON_MODIFY() 调用中使用通配符,因此一种可能的方法是执行以下步骤:

  • 使用 OPENJSON() 和包含 line 键的显式模式从存储的 JSON 中解析 $.items 数组。
  • 为此数组的每一项设置 disc 键的新值。
  • 使用 FOR JSON PATH 再次生成 JSON。
  • 将 table 更新为 JSON_MODIFY()

Table:

create table #temp_data (json_text nvarchar(max))
insert into #temp_data (json_text)
VALUES (N'
{
   "curr":"USD",
   "items":[
      {"line":1, "disc":10},
      {"line":2, "disc":11},
      {"line":3, "disc":12}
   ]
}')

声明:

UPDATE #temp_data
SET json_text = JSON_MODIFY(
   json_text,
   '$.items',
   (
   SELECT line, 100 AS disc
   FROM OPENJSON(json_text, '$.items') WITH (line int '$.line')
   FOR JSON PATH
   )
)   

结果:

json_text
{
   "curr":"USD",
   "items":[{"line":1,"disc":100},{"line":2,"disc":100},{"line":3,"disc":100}]
}

我们实际上不需要解析 JSON 的其余部分,我们只需要 $.items 部分。所以我们可以 APPLY 属性 和 OPENJSON,然后用 JSON_MODIFY 重新组合它:

UPDATE t
SET json_text = JSON_MODIFY(t.json_text, '$.items', v.items)
FROM temp_data t
CROSS APPLY (
    SELECT line, disc = 100
    FROM OPENJSON(t.json_text, '$.items') WITH (line int) AS items
    FOR JSON PATH
  ) v(items);

WITH 块中,我们需要添加我们不修改的所有属性,然后在内部 SELECT 我们添加我们想要更改的任何列。