json - 如何在 mssql 中更新 JSON 中的嵌套数组

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

我正在使用 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,它应该用我传递的 feed 更新整个 feed。

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

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');

最佳答案

@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"}]}]} |
+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

接下来,我匹配了您的更新规则:更新一个嵌套的 JSON 值,该值仅限于特定的 CustomerId (9ee07040-c001-11e9-b29a-55eb3439cd7c) 和一个 feedName (ccsdcdscsdc)。

正如我提到的,我们需要先“解压”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< 应用过滤器/strong>.

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)。

这样,就可以为“feed”的 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”。我不清楚您要更新的内容,因此我使用了格式 进行测试/示例。

我希望这能让您朝着正确的方向前进。编码愉快!

这是可以在 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;

编辑:

i wanted to update the feed with the given feedId with the whole new feed

要用全新的提要替换一个“提要”,您可以执行以下操作:

-- 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 without its optional second parameter returns only the first argument as a result. Since JSON_QUERY always returns valid JSON, FOR JSON knows that this result does not have to be escaped.

如果您在没有 JSON_QUERY 的情况下传递 @MyNewJson,您的新 json 将被转义(例如,“customerName”变为\"customerName\"),就像它被存储为纯文本一样。 JSON_QUERY 将返回未转义的有效 JSON,这在您的情况下是必需的。

另请注意,我为替换整个提要与单个项目值所做的唯一更改是切换

'$.feeds[' + Config_CTE.[key] + '].format'

'$.feeds[' + Config_CTE.[key] + ']'.

关于json - 如何在 mssql 中更新 JSON 中的嵌套数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57591635/

相关文章:

java - Spring jpa native 查询在有 0 个结果时抛出 MySQLSyntaxErrorException

java - 如何使用 Spring Data JPA 获得域驱动设计架构?

python - 使用 Python 优雅且可扩展地将有效 JSON 的各行文件转换为 CSV

android - 如何从 Soap Web 服务填充微调器中的所有 json 数组?

javascript - 如何使用服务器的 JSON 响应动态填充灰尘模板?

sql - TSQL 月度报告按组求和

c# - 使用 SqlBulkCopy 时跳过现有记录

javascript - Angularjs oauth 弹出窗口,等待 JSON 响应

sql - 执行更新时 SQL 中的行数

java - Spring boot资源文件夹中访问xml的问题