【问题标题】:SQL-SERVER: JSON_MODIFY on json column with "contains" field matchSQL-SERVER:json 列上的 JSON_MODIFY 与“包含”字段匹配
【发布时间】:2020-08-10 19:39:56
【问题描述】:

我正在尝试弄清楚如何修改存储在我的表 (SQL SERVER) 的列中的 json。

我只想删除与特定字符串匹配的 JSON 属性。

假设我们的表中有一条记录,此 JSON 在名为“profile”的列中 (nvarchar(max)):

{ 
  name: "goofy",
  class_cod_x: "1345",
}

然后另一条记录呈现这个 JSON:

{ 
  name: "donald",
  class_cod_y: "1457",
}

现在我们要搜索并更新记录中包含 startsWith“class_cod”属性的所有 JSON。

我想从该列中删除所有“class_cod..”属性。

我可以想象这样一个查询:

UPDATE myTable SET profile = JSON_MODIFY( profile , "startsWith(class_cod)" , null)

这可能吗?在那种情况下,哪个是正确的语法? 提前致谢!

更新 预期输出:

{ 
  name: "goofy",
}

{ 
  name: "donald",
}

“class_cod”字段已完全删除。

更新 2

  • SQL SERVER 版本:Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (X64)

  • “name”和“class_cod..”不是 json 列中唯一可能的字段。 该 JSON 基于可能配置的枚举。

  • JSON 是否可能包含多个“class_cod..”字段。 (极其罕见但可能)

    {
      name: mario,
      class_cod_10: 22,
      class_cod_20: 31,
    }
    

【问题讨论】:

  • 预期输出是什么?
  • 对不起,我会用预期的输出更新答案
  • 您的 SQl Server 版本是多少?是nameclass_cod_? JSON对象中唯一可用的键?每个 JSON 对象是否只包含一个 class_cod_? 键?谢谢。
  • @Zhorov 刚刚更新了您需要的更多信息,提前致谢
  • 好的,那么动态语句应该是您的首选。

标签: sql json sql-server nvarchar


【解决方案1】:

我不认为您可以在JSON_MODIFY() 中为path 参数使用通配符,如果profile 列中的JSON 有多个class_cod_* 键,您可以尝试生成并执行动态陈述。最后一条语句包含一个 UPDATE 语句,用于表中所有行的所有 JSON 对象中的每个不同的 class_cod_* 键。注意,需要使用lax模式(默认)来指定path引用的属性不必存在:

表:

CREATE TABLE Data (profile nvarchar(max));
-- Rows with one `class_cod_*` key
INSERT INTO Data (profile) VALUES (N'{"name":"goofy","class_cod_x":"1345"}')
INSERT INTO Data (profile) VALUES (N'{"name":"donald","class_cod_y":"1457"}')
-- Row without `class_cod_*` key
INSERT INTO Data (profile) VALUES (N'{"name":"tom"}')
-- Row with one `class_cod_*` key and other keys
INSERT INTO Data (profile) VALUES (N'{"name":"goofy","class_cod_x":"1345","age":10}')
-- Row with two `class_cod_*` keys
INSERT INTO Data (profile) VALUES (N'{"name":"jerry", "class_cod_x":"1345", "class_cod_y":"1345"}')

声明:

DECLARE @stm nvarchar(max)
SELECT @stm = (
   SELECT CONCAT(
      CONCAT('UPDATE Data SET profile = JSON_MODIFY(profile, ''lax $."', t.[key], '"'', null)'),
      '; '
   )   
   FROM (
      SELECT DISTINCT j.[key]
      FROM Data d
      CROSS APPLY OPENJSON(d.profile) j
      WHERE j.[key] LIKE N'class_cod_%' 
   ) t
   FOR XML PATH('')
)
PRINT @stm
EXEC sp_executesql @stm

结果:

profile
{"name":"goofy"}
{"name":"donald"}
{"name":"tom"}
{"name":"goofy","age":10}
{"name":"jerry"}

【讨论】:

  • 成功了,非常感谢@Zhorov!!在profile列是JSON数组的类似情况下,是否可以应用此解决方案?
  • @Tommolo,是的,为什么不呢。您将需要使用双精度 CROSS APPLY 来获取此 JSON 数组中每个 JSON 对象的索引,因为 path 将类似于 $[0].class_cod_x。但是测试数据是必要的,或者这里可能是另一个问题。谢谢。
【解决方案2】:

一种方法是创建动态更新语句并手动运行生成的更新查询。像这样。

SELECT 'UPDATE MYTABLE SET PROFILE=JSON_MODIFY(profile ,''$.' +x.[key]+ ''', null)'
FROM MYTABLE T
CROSS APPLY OPENJSON (profile, '$') x 
WHERE x.[key] LIKE '%class_cod%'

此查询将创建如下更新语句列表。

UPDATE MYTABLE SET PROFILE=JSON_MODIFY(profile ,'$.class_cod_x', null)
UPDATE MYTABLE SET PROFILE=JSON_MODIFY(profile ,'$.class_cod_y', null)

假设:每条 JSON 记录仅包含一次密钥 class_cod_*。希望只有有限的行可以手动运行更新语句

Check Demo Here

【讨论】:

  • 感谢 Arun 的回答,它适用于没有多个 class_cod 键的 json。正如我在更新中所说,这种情况是可能的,但极为罕见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
相关资源
最近更新 更多