JSON_MODIFY 不适用于可变参数

Posted

技术标签:

【中文标题】JSON_MODIFY 不适用于可变参数【英文标题】:JSON_MODIFY does not work with variable parameter 【发布时间】:2022-01-12 12:50:10 【问题描述】:

我有一个修改一些 JSON 的 SQL 查询。我正在遍历数据并根据迭代修改部分 JSON。

为此,我需要将可变参数传递给 JSON_MODIFY,但由于某种原因,它不起作用!

SET @json = JSON_MODIFY(@ProData, '$.' + @ProKey + '.hasAnswer', CAST(1 as BIT))

我也尝试将整个表达式作为变量传递:

DECLARE @hasAnswerPath VARCHAR(100);
SET @hasAnswerPath = '$.' + @ProKey + '.hasAnswer';
SET @json = JSON_MODIFY(@ProData, @hasAnswerPath, CAST(1 as BIT))

但是它有相同的输出,hasAnswer被添加到JSON的根而不是@ProKey指定的元素中。

这很好用:

SET @json = JSON_MODIFY(@ProData, '$.SomeName1.hasAnswer', CAST(1 as BIT))

就像@ProKey 被忽略了。

完整查询:

BEGIN TRAN

DECLARE @ProID as uniqueidentifier;
DECLARE @ProData as nvarchar(max);
DECLARE @ProKey as varchar(200);

DECLARE ProCursor CURSOR FOR
    SELECT Id, [Data] FROM [dbo].[PRO]

OPEN ProCursor;
FETCH NEXT FROM ProCursor INTO @ProID, @ProData;
WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @json NVARCHAR(max);

    DECLARE DataCursor CURSOR FOR
        SELECT [key] FROM OPENJSON(@ProData) WHERE type = 5; --5 is object data
        
    OPEN DataCursor;
    FETCH NEXT FROM DataCursor INTO @ProKey;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @json=JSON_MODIFY(@ProData, '$.' + @ProKey + '.hasAnswer', CAST(1 as BIT))
        SET @json=JSON_MODIFY(@json,'$.' + @ProKey + '.questionType','intro')
        
        FETCH NEXT FROM DataCursor INTO @ProKey;
    END;

    UPDATE [dbo].[PRO]
    SET [Data] = @json
    WHERE Id = @ProID

    PRINT @json

    CLOSE DataCursor;
    DEALLOCATE DataCursor;

    FETCH NEXT FROM ProCursor INTO @ProID, @ProData;
END
CLOSE ProCursor;
DEALLOCATE ProCursor;

ROLLBACK

示例 JSON:

 
     "SomeName1": 
        "header": "Some text",
        "answer": 
            "type": "specified",
            "numberValue": 1.0
        
     ,
     "SomeName2": 
        "header": "Some text",
        "answer": 
            "type": "specified",
            "numberValue": 4.0
         
     ,
     "SomeName3": 
         "header": "Some text",
         "answer": 
             "type": "specified",
             "numberValue": 2.0
        
     
 

预期结果:

,
    "SomeName1": 
        "header": "Some text",
        "answer": 
            "type": "specified",
            "numberValue": 1.0
        
        "hasAnswer": true,
        "questionType": "intro",
     

实际结果:

,
    "SomeName1": 
            "header": "Some text",
            "answer": 
                "type": "specified",
                "numberValue": 1.0
            
         
     ,
     "hasAnswer":true,
     "questionType":"intro"
 

我在这里做错了什么?

【问题讨论】:

MS SQL Server 2019。 您未发布的代码可能有问题。有什么有用的可以补充吗?像 json 的样子和意想不到的结果? 问题更新了更多信息。 它可以很容易地通过创建一个包含列 Id 和 Data 的新表并插入 NewGuid 和 JSON 样本来测试 哦,那是复制/粘贴错误!我已经编辑了问题。 【参考方案1】:

您似乎无意中覆盖了变量:

-- first iteration

SET @json=JSON_MODIFY(@ProData, '$.' + @ProKey + '.hasAnswer', CAST(1 as BIT))
-- @json contains the @prodata after modification to first key (@prodata itself is not changed)

SET @json=JSON_MODIFY(@json,'$.' + @ProKey + '.questionType','intro')
-- @json (its first key to be more precise) is modified further

但在下一次迭代中,此行会将修改后的 @json 恢复为 @prodata 的原始值。只有最后一个键会保留修改:

-- second iteration

SET @json=JSON_MODIFY(@ProData, '$.' + @ProKey + '.hasAnswer', CAST(1 as BIT))
-- you just overwrote your modifications with the value inside @prodata

解决办法是重新编排一下代码,可以在循环外初始化@json

【讨论】:

但问题不在于 json 或 ProData,而在于 ProKey 不能作为 JSON_MODIFY 中的参数。 那我就不知道了。您的代码中有一个明显的缺陷,它只会更新最后一个键。它无法更新父级。 $..foonull 应该抛出异常而不是修改根对象。可能是你的 JSON 嵌套了两个你没有发布的深度。 嗯..我会试着仔细看看,你可能是对的!.. 你完全正确!已将解决方案移至问题,非常感谢!

以上是关于JSON_MODIFY 不适用于可变参数的主要内容,如果未能解决你的问题,请参考以下文章

用于打印可变参数的宏,可以选择无参数

将带有参数的 printf 用于可变参数函数?

用于可变长度参数数组的 PHPDoc

用于定义具有可变参数的函数的嵌套#define 问题

为啥 Room 实体不适用于 Android 中的不可变属性

用于打印可变参数的宏,可选择无参数