如何在 mssql 中更新 JSON 中的嵌套数组
Posted
技术标签:
【中文标题】如何在 mssql 中更新 JSON 中的嵌套数组【英文标题】:How to update a nested array in JSON in mssql 【发布时间】:2019-12-26 17:35:46 【问题描述】:我正在使用 mssql 并且一列有 json 数据,我想通过传递 id 来更新该 json 的那部分,它是一个数组。
"customerName":"mohan",
"custId":"e35273d0-c002-11e9-8188-a1525f580dfd",
"feeds":[
"feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e",
"feedName":"ccsdcdscsdc",
"format":"Excel",
"sources":[
"sourceId":69042417,
"name":"TV 2 Livsstil"
,
"sourceId":69042419,
"name":"Turk Max"
]
,
"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e",
"feedName":"dfgdfgdfgdfgsdfg",
"format":"XmlTV",
"sources":[
"sourceId":69042417,
"name":"TV 2 Livsstil"
,
"sourceId":69042419,
"name":"Turk Max"
]
]
假设我要通过customerId
和feedId
,它应该用我通过的提要更新整个提要。
我尝试了以下查询,但没有帮助。
UPDATE
ExtractsConfiguration.dbo.Customers
SET
configJSON = JSON_MODIFY(configJSON,'$.feeds[]',"feedName":"ccsdcdscsdc")
WHERE
CustomerId = '9ee07040-c001-11e9-b29a-55eb3439cd7c'
AND json_query(configJSON,'$.feeds[].feedId'='57f221d0-c310-11e9-8af7-cf1cf42fc72e');
【问题讨论】:
【参考方案1】:@mohan,这是一个棘手的问题,我将其视为对自己的挑战。有一种方法可以按照您的要求更新嵌套 JSON 对象的值,但是,它并不像看起来那么简单。
因为您在数组中工作,所以需要数组的索引来更新嵌套值。在您的情况下,您不知道数组中的索引,但是,您确实有一个可以引用的键值,在这种情况下,您的 feedName。
为了更新您的值,您首先需要“解压”您的 JSON,以便您可以过滤特定的 feedName,在您的示例中为“ccsdcdscsdc”。
这是一个您可以在 SSMS 中运行的示例,它将帮助您朝着正确的方向前进。
我创建的第一件事是@Customers TABLE 变量,用于模仿您在示例中显示的数据结构并插入您的示例数据。
DECLARE @Customers TABLE ( CustomerId VARCHAR(50), configJSON VARCHAR(MAX) );
INSERT INTO @Customers ( CustomerID, configJSON ) VALUES ( '9ee07040-c001-11e9-b29a-55eb3439cd7c', '"customerName":"mohan","custId":"e35273d0-c002-11e9-8188-a1525f580dfd","feeds":["feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"],"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e","feedName":"dfgdfgdfgdfgsdfg","format":"XmlTV","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"]]' );
对@Customers 运行 SELECT 会返回以下内容:
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CustomerId | configJSON |
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 9ee07040-c001-11e9-b29a-55eb3439cd7c | "customerName":"mohan","custId":"e35273d0-c002-11e9-8188-a1525f580dfd","feeds":["feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"],"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e","feedName":"dfgdfgdfgdfgsdfg","format":"XmlTV","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"]] |
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
接下来,我匹配了您的更新规则:更新限制为特定 CustomerId (9ee07040-c001-11e9-b29a-55eb3439cd7c) 和 feedName (ccsdcdscsdc) 的嵌套 JSON 值。
就像我提到的,我们需要先“解压”JSON,因为我们不知道应该更新的特定键(索引)值。完成这两项任务(解包/更新)的最简单方法是使用公用表表达式 (CTE)。
所以,我是这样做的:
;WITH Config_CTE AS (
SELECT * FROM @Customers AS Customer
CROSS APPLY OPENJSON( configJSON, '$.feeds' ) AS Config
WHERE
Customer.CustomerId = '9ee07040-c001-11e9-b29a-55eb3439cd7c'
AND JSON_VALUE( Config.value, '$.feedName' ) = 'ccsdcdscsdc'
)
UPDATE Config_CTE
SET configJSON = JSON_MODIFY( configJSON, '$.feeds[' + Config_CTE.[key] + '].format', 'MS Excel' );
CTE 允许我们“解包”(我编造了这个词,因为它看起来很合适)包含在 configJSON 中的 JSON,然后允许我们对 feedName。
AND JSON_VALUE( Config.value, '$.feedName' ) = 'ccsdcdscsdc'
您还会注意到我们包含了 CustomerId 规则:
Customer.CustomerId = '9ee07040-c001-11e9-b29a-55eb3439cd7c'
CustomerId 和 feedName 都可以很容易地成为 SQL 变量。
那么,这是做什么的呢?如果我们要查看 Configs_CTE 结果集(通过将 UPDATE... 更改为 SELECT * FROM Config_CTE ),我们会看到:
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+
| CustomerId | configJSON | key | value | type |
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+
| 9ee07040-c001-11e9-b29a-55eb3439cd7c | "customerName":"mohan","custId":"e35273d0-c002-11e9-8188-a1525f580dfd","feeds":["feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"],"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e","feedName":"dfgdfgdfgdfgsdfg","format":"XmlTV","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"]] | 0 | "feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"] | 5 |
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+
这里有很多信息,但我们真正关心的是“关键”列,因为它包含我们要更新的提要索引(在本例中为 0 )。
这样,对于 feedName 为“ccsdcdscsdc”的“feed”,能够完成从“Excel”到“MS Excel”的请求和更新格式。
这家伙(注意 Config_CTE.[key] 的使用):
UPDATE Config_CTE
SET configJSON = JSON_MODIFY( configJSON, '$.feeds[' + Config_CTE.[key] + '].format', 'MS Excel' );
成功了吗?让我们看看更新后的表格数据。
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CustomerId | configJSON |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 9ee07040-c001-11e9-b29a-55eb3439cd7c | "customerName":"mohan","custId":"e35273d0-c002-11e9-8188-a1525f580dfd","feeds":["feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"MS Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"],"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e","feedName":"dfgdfgdfgdfgsdfg","format":"XmlTV","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"]] |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
这是更新后的“美化”JSON(很确定不是我编造的)。
"customerName": "mohan",
"custId": "e35273d0-c002-11e9-8188-a1525f580dfd",
"feeds": [
"feedId": "57f221d0-c310-11e9-8af7-cf1cf42fc72e",
"feedName": "ccsdcdscsdc",
"format": "MS Excel",
"sources": [
"sourceId": 69042417,
"name": "TV 2 Livsstil"
,
"sourceId": 69042419,
"name": "Turk Max"
]
,
"feedId": "59bbd360-c312-11e9-8af7-cf1cf42fc72e",
"feedName": "dfgdfgdfgdfgsdfg",
"format": "XmlTV",
"sources": [
"sourceId": 69042417,
"name": "TV 2 Livsstil"
,
"sourceId": 69042419,
"name": "Turk Max"
]
]
好了,你知道了,feedName“ccsdcdscsdc”的格式已从“Excel”更新为“MS Excel”。我不清楚您要更新什么,所以我使用 format 进行测试/示例。
我希望这能让你朝着正确的方向前进。编码愉快!
这是可以在 SSMS 中运行的完整示例:
-- CREATE A CUSTOMERS TABLE TO MIMIC SCHEMA --
DECLARE @Customers TABLE ( CustomerId VARCHAR(50), configJSON VARCHAR(MAX) );
INSERT INTO @Customers ( CustomerID, configJSON ) VALUES ( '9ee07040-c001-11e9-b29a-55eb3439cd7c', '"customerName":"mohan","custId":"e35273d0-c002-11e9-8188-a1525f580dfd","feeds":["feedId":"57f221d0-c310-11e9-8af7-cf1cf42fc72e","feedName":"ccsdcdscsdc","format":"Excel","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"],"feedId":"59bbd360-c312-11e9-8af7-cf1cf42fc72e","feedName":"dfgdfgdfgdfgsdfg","format":"XmlTV","sources":["sourceId":69042417,"name":"TV 2 Livsstil","sourceId":69042419,"name":"Turk Max"]]' );
-- SHOW CURRENT DATA --
SELECT * FROM @Customers;
-- UPDATE "format" FROM "Excel" to "MS Excel" FOR feedName: ccsdcdscsdc --
WITH Config_CTE AS (
SELECT * FROM @Customers AS Customer
CROSS APPLY OPENJSON( configJSON, '$.feeds' ) AS Config
WHERE
Customer.CustomerId = '9ee07040-c001-11e9-b29a-55eb3439cd7c'
AND JSON_VALUE( Config.value, '$.feedName' ) = 'ccsdcdscsdc'
)
UPDATE Config_CTE
SET configJSON = JSON_MODIFY( configJSON, '$.feeds[' + Config_CTE.[key] + '].format', 'MS Excel' );
-- SHOW UPDATED DATA --
SELECT * FROM @Customers;
编辑:
我想用给定的 feedId 用全新的方式更新提要 饲料
要用全新的提要替换一个“提要”,您可以执行以下操作:
-- REPLACE AN ENTIRE JSON ARRAY OBJECT --
DECLARE @MyNewJson NVARCHAR(MAX) = '"feedId": "this_is_an_entirely_new_node","feedName": "ccsdcdscsdc","format": "NewFormat","sources": ["sourceId": 1,"name": "New Source 1","sourceId": 2,"name": "New Source 2"]';
WITH Config_CTE AS (
SELECT * FROM @Customers AS Customer
CROSS APPLY OPENJSON( configJSON, '$.feeds' ) AS Config
WHERE
Customer.CustomerId = '9ee07040-c001-11e9-b29a-55eb3439cd7c'
AND JSON_VALUE( Config.value, '$.feedName' ) = 'ccsdcdscsdc'
)
UPDATE Config_CTE
SET configJSON = JSON_MODIFY( configJSON, '$.feeds[' + Config_CTE.[key] + ']', JSON_QUERY( @MyNewJson ) );
运行后,提要现在显示为:
"customerName": "mohan",
"custId": "e35273d0-c002-11e9-8188-a1525f580dfd",
"feeds": [
"feedId": "this_is_an_entirely_new_node",
"feedName": "ccsdcdscsdc",
"format": "NewFormat",
"sources": [
"sourceId": 1,
"name": "New Source 1"
,
"sourceId": 2,
"name": "New Source 2"
]
,
"feedId": "59bbd360-c312-11e9-8af7-cf1cf42fc72e",
"feedName": "dfgdfgdfgdfgsdfg",
"format": "XmlTV",
"sources": [
"sourceId": 69042417,
"name": "TV 2 Livsstil"
,
"sourceId": 69042419,
"name": "Turk Max"
]
]
注意在更新中使用JSON_QUERY( @MyNewJson )
。这很重要。
来自微软的文档:
没有可选第二个参数的 JSON_QUERY 仅返回 结果是第一个论点。由于 JSON_QUERY 总是返回有效 JSON,FOR JSON 知道这个结果不必转义。
如果您在没有 JSON_QUERY 的情况下传递 @MyNewJson,您的新 json 将被转义(例如,“customerName”变为 \"customerName\"),就好像它被存储为纯文本一样。 JSON_QUERY 将返回未转义的有效 JSON,这在您的情况下是必需的。
另请注意,我为替换整个提要与单个项目值所做的唯一更改是切换
'$.feeds[' + Config_CTE.[key] + '].format'
到
'$.feeds[' + Config_CTE.[key] + ']'.
【讨论】:
我想用给定的 feedId 用全新的提要更新提要,所以我尝试了以下 1 UPDATE Customers SET configJSON = JSON_MODIFY(configJSON, SELECT value FROM ExtractsConfiguration.dbo.Customers AS Customer CROSS应用 OPENJSON( configJSON, '$.feeds' ) 作为配置在哪里 Customer.CustomerId = 'e35273d0-c002-11e9-8188-a1525f580dfd' AND JSON_VALUE( Config.value, '$.feedId' ) = '57f221d0-c310-11e9- 8af7-cf1cf42fc72e', new feed json) 是不是一个好方法。它给出的错误 @mohan,一旦您了解了正在发生的事情的基本原理,这将非常简单。查看上面我的答案的编辑,我将展示如何做到这一点。以上是关于如何在 mssql 中更新 JSON 中的嵌套数组的主要内容,如果未能解决你的问题,请参考以下文章
vue.js - 使用原始 json 中的嵌套数组时,递归组件不会更新
如何使用 NSDictionary 收集嵌套在数组中的 JSON 数据