【问题标题】:How to update a nested array in JSON in mssql如何在 mssql 中更新 JSON 中的嵌套数组
【发布时间】: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');

【问题讨论】:

    标签: json sql-server spring-data-jpa json-query


    【解决方案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,一旦您了解了正在发生的事情的基本原理,这将非常简单。查看上面我的答案的编辑,我将展示如何做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 2020-07-08
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 2021-10-14
    相关资源
    最近更新 更多