【问题标题】:TSQL how to merge two Json arraysTSQL如何合并两个Json数组
【发布时间】:2019-07-18 12:07:32
【问题描述】:

如何将新的数组元素合并到现有的 Json 属性中? 我们的两个 json 对象看起来像这样,我们想将第二个 json 对象的项目附加到第一个 json 对象。 (查看预期结果)

有没有办法通过 JSON_MODIFY 实现​​这一点? 微软文档并没有真正显示将多个元素合并到现有数组中的任何示例。只有一个元素。但是我们有一个需要合并的多个元素的列表。

编辑: JSON_MODIFY(@json1, 'append $.Items', JSON_QUERY(@json2)) 似乎创建了新的数组括号,而不是将项目合并到数组中。

Json 对象 1:

DECLARE @json1 NVARCHAR(MAX) = '{
    "id": 1,
    "Items": [
        {
            "id": 1,
            "name" : "Item #1"
        },
        {
            "id": 2,
            "name" : "Item #2"
        }
    ]
}'

Json 对象 2:

DECLARE @json2 NVARCHAR(MAX)='{
    "Items": [
        {
            "id": 3,
            "name": "Item #3"
        },
        {
            "id": 4,
            "name": "Item #4"
        }
    ]
}'

期望的结果:

{
    "id": 1,
    "Items": [
        {
            "id": 1,
            "name": "Item #1"
        },
        {
            "id": 2,
            "name": "Item #2"
        },
        {
            "id": 3,
            "name": "Item #3"
        },
        {
            "id": 4,
            "name": "Item #4"
        }
    ]
}

【问题讨论】:

  • 在 JSON 中,数组是按构造排序的。从您的数据来看,您似乎并不完全需要“追加”。是对的吗?这将简化答案。

标签: json tsql


【解决方案1】:

你的问题可以解决

SELECT  dbo.udf_native_json_merge(@json1,@json2,null)

我们在尝试在 MS SQL 中合并 JSON 时遇到了类似的问题。我们还希望它是递归的,并允许我们为“union”、“concat”和“replace”等数组定义策略。

我们的 JSON 操作解决方案(如合并、JSON 路径表达式等)是开源的,并且可用 @Github

请随意使用、评论和贡献,以便我们进一步改进 MS SQL 的 JSON 方法。

【讨论】:

    【解决方案2】:

    这很麻烦,但可以通过 SQL Server 内置的 JSON 支持来实现。

    首先,设置适当的样本数据(请在您以后的问题中保存我们这一步):

    DECLARE @Json1 nvarchar(max) = 
    '{
        "id": 1,
        "Items": [
            {
                "id": 1,
                "name" : "Item #1"
            },
            {
                "id": 2,
                "name" : "Item #2"
            }
        ]
    }',
    
    @Json2 nvarchar(max) = 
    '{
        "Items": [
            {
                "id": 3,
                "name": "Item #3"
            },
            {
                "id": 4,
                "name": "Item #4"
            }
        ]
    }';
    

    然后,为每个具有公共表表达式的变量包装一个包含openjson 和json_query 的union all 查询:

    With cteArray as
    (
        SELECT *
        FROM OPENJSON(JSON_QUERY(@Json1, '$.Items'))
        WITH(
            Id int '$.id',
            Name varchar(100) '$.name'
        )
        UNION ALL 
        SELECT *
        FROM OPENJSON(JSON_QUERY(@Json2, '$.Items'))
        WITH(
            Id int '$.id',
            Name varchar(100) '$.name'
        )
    )
    

    联合所有查询的结果是这样的:

    Id      Name
    1       Item #1
    2       Item #2
    3       Item #3
    4       Item #4
    

    然后,使用json_value 从第一个json 中选择id,并添加一个子查询以使用for json path 从cte 中选择所有内容。添加另一个for json path 并在外部查询中指定without_array_wrapper:

    SELECT JSON_VALUE(@Json1, '$.id') As id,
            (
                SELECT * 
                FROM cteArray
                FOR JSON PATH
            ) as Items
    FOR JSON PATH,
    WITHOUT_ARRAY_WRAPPER
    

    最终结果:

    {
        "id": "1",
        "Items": [{
                "Id": 1,
                "Name": "Item #1"
            }, {
                "Id": 2,
                "Name": "Item #2"
            }, {
                "Id": 3,
                "Name": "Item #3"
            }, {
                "Id": 4,
                "Name": "Item #4"
            }
        ]
    }
    

    你可以在Db<>Fiddle看到现场演示

    【讨论】:

    • 嗯,遗憾的是它不仅仅是一个简单的 json_modify 调用。我们有几个具有不同属性的项目需要合并到数组中,但我们将看看我们可以用这个例子做什么。谢谢
    • 不,SQL Server 中的 json 支持非常基础,恐怕。除了明显、直接的简单操作之外,您必须编写(相对)大量代码。
    【解决方案3】:

    不漂亮,但这会合并文本和对象元素。我敢肯定它不是防弹的。仅作为潜在解决方案提供。

    Declare @json1 nvarchar(max) = '{"id":1,"messages":[{"type":"Info","text":"message1"},{"type":"Info","text":"message2"}]}'
    Declare @json2 nvarchar(max) = '{"id":1,"messages":["justPlanText",{"type":"Info","text":"message3"},{"type":"Info","text":"message4"}]}'
    
    select @json1 = case 
                    when isjson(m.value) = 1 then
                      json_modify(@json1,'append $.messages',json_query(m.value))
                    else 
                      json_modify(@json1,'append $.messages',m.value)
                    end
    from openjson(json_query(@json2,'$.messages')) m
    
    select @json1
    

    @json1 的结果:

    {"id":1,"messages":[{"type":"Info","text":"message1"},{"type":"Info","text":"message2"},"justPlanText",{"type":"Info","text":"message3"},{"type":"Info","text":"message4"}]}
    

    【讨论】:

    • 这个想法看起来很有希望;但是,如果您从问题中复制了 json 的结构,我认为您的答案会更容易申请原始海报。
    猜你喜欢
    • 1970-01-01
    • 2019-03-19
    • 2018-09-13
    • 2017-08-22
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    • 2014-03-05
    • 2011-10-02
    相关资源
    最近更新 更多