如何在 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"
            
         ]
      
   ]

假设我要通过customerIdfeedId,它应该用我通过的提要更新整个提要。

我尝试了以下查询,但没有帮助。

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'

CustomerIdfeedName 都可以很容易地成为 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 中的嵌套数组的主要内容,如果未能解决你的问题,请参考以下文章

更新Couchbase中的嵌套json数组字段

vue.js - 使用原始 json 中的嵌套数组时,递归组件不会更新

如何在 Ios 中解析数组数据中的嵌套 Json 对象

如何使用 NSDictionary 收集嵌套在数组中的 JSON 数据

如何使用 pyspark 在 aws 胶水中展平嵌套 json 中的数组?

Mantle 2.0 无法为嵌套数组中的符号解析 JSON