In Sql Server 2016 it's not possible to use variables as json path in JSON_MODIFY, so I'm not sure if there's an elegant solution for this problem.

If you have Sql Server 2017, then it seems to be possible.

create function dbo.fn_json_merge
(
    @a nvarchar(max),
    @b nvarchar(max)
)
returns nvarchar(max)
as
begin
    if left(@a, 1) = '{' and left(@b, 1) = '{' begin
        select
            @a = case when d.[type] in (4,5) then json_modify(@a, concat('$.',d.[key]), json_query(d.[value])) else @a end,
            @a = case when d.[type] not in (4,5) then json_modify(@a, concat('$.',d.[key]), d.[value]) else @a end
        from openjson(@b) as d;
    end else if left(@a, 1) = '[' and left(@b, 1) = '{' begin
        select @a = json_modify(@a, 'append $', json_query(@b));
    end else begin
        select @a = concat('[', @a, ',', right(@b, len(@b) - 1));
    end;

    return @a;
end;

Couple of notes:

  • For the sake of simplicity I didn't add checking that both objects are actually valid json;
  • I don't know if there's a better way to check that given string is json array or json object;
  • It's not possible to add first element of array with json_modify so there's a fallback to simple CONCAT in case first string is an object and second is an array;
  • I had to creatively use JSON_QUERY function so jsons will be inserted correctly;
  • I've used the fact that if you assign the variable in SELECT statement then you can use previous value of the variable in the assignment statement;

sql server fiddle demo

postgresql fiddle example

update I've added a bit improved version which should work with different types of values better:

create function dbo.fn_json_merge
(
    @a nvarchar(max),
    @b nvarchar(max)
)
returns nvarchar(max)
as
begin
    if left(@a, 1) = '{' and left(@b, 1) = '{' begin
        select @a =
            case
                when d.[type] in (4,5) then
                    json_modify(@a, concat('$.',d.[key]), json_query(d.[value]))
                when d.[type] in (3) then
                    json_modify(@a, concat('$.',d.[key]), cast(d.[value] as bit))
                when d.[type] in (2) and try_cast(d.[value] as int) = 1 then
                    json_modify(@a, concat('$.',d.[key]), cast(d.[value] as int))
                when d.[type] in (0) then
                    json_modify(json_modify(@a, concat('lax $.',d.[key]), 'null'), concat('strict $.',d.[key]), null)
                else
                    json_modify(@a, concat('$.',d.[key]), d.[value])
            end
        from openjson(@b) as d
    end else if left(@a, 1) = '[' and left(@b, 1) = '{' begin
        select @a = json_modify(@a, 'append $', json_query(@b))
    end else begin
        select @a = concat('[', @a, ',', right(@b, len(@b) - 1))
    end

    return @a
end

sql fiddle demo

Answer from roman on Stack Overflow
Top answer
1 of 9
7

In Sql Server 2016 it's not possible to use variables as json path in JSON_MODIFY, so I'm not sure if there's an elegant solution for this problem.

If you have Sql Server 2017, then it seems to be possible.

create function dbo.fn_json_merge
(
    @a nvarchar(max),
    @b nvarchar(max)
)
returns nvarchar(max)
as
begin
    if left(@a, 1) = '{' and left(@b, 1) = '{' begin
        select
            @a = case when d.[type] in (4,5) then json_modify(@a, concat('$.',d.[key]), json_query(d.[value])) else @a end,
            @a = case when d.[type] not in (4,5) then json_modify(@a, concat('$.',d.[key]), d.[value]) else @a end
        from openjson(@b) as d;
    end else if left(@a, 1) = '[' and left(@b, 1) = '{' begin
        select @a = json_modify(@a, 'append $', json_query(@b));
    end else begin
        select @a = concat('[', @a, ',', right(@b, len(@b) - 1));
    end;

    return @a;
end;

Couple of notes:

  • For the sake of simplicity I didn't add checking that both objects are actually valid json;
  • I don't know if there's a better way to check that given string is json array or json object;
  • It's not possible to add first element of array with json_modify so there's a fallback to simple CONCAT in case first string is an object and second is an array;
  • I had to creatively use JSON_QUERY function so jsons will be inserted correctly;
  • I've used the fact that if you assign the variable in SELECT statement then you can use previous value of the variable in the assignment statement;

sql server fiddle demo

postgresql fiddle example

update I've added a bit improved version which should work with different types of values better:

create function dbo.fn_json_merge
(
    @a nvarchar(max),
    @b nvarchar(max)
)
returns nvarchar(max)
as
begin
    if left(@a, 1) = '{' and left(@b, 1) = '{' begin
        select @a =
            case
                when d.[type] in (4,5) then
                    json_modify(@a, concat('$.',d.[key]), json_query(d.[value]))
                when d.[type] in (3) then
                    json_modify(@a, concat('$.',d.[key]), cast(d.[value] as bit))
                when d.[type] in (2) and try_cast(d.[value] as int) = 1 then
                    json_modify(@a, concat('$.',d.[key]), cast(d.[value] as int))
                when d.[type] in (0) then
                    json_modify(json_modify(@a, concat('lax $.',d.[key]), 'null'), concat('strict $.',d.[key]), null)
                else
                    json_modify(@a, concat('$.',d.[key]), d.[value])
            end
        from openjson(@b) as d
    end else if left(@a, 1) = '[' and left(@b, 1) = '{' begin
        select @a = json_modify(@a, 'append $', json_query(@b))
    end else begin
        select @a = concat('[', @a, ',', right(@b, len(@b) - 1))
    end

    return @a
end

sql fiddle demo

2 of 9
4

I have a solution for your issue. I found it while trying to merge 2 different JSON objects and I used JSON_MODIFY and OPENJSON functions.

Sample data:

JSON1: {"a": 1, "b": 2, "c": 3}
JSON2: {"d": 4, "e": 5}

Here the solution

DECLARE @vJSON NVARCHAR(MAX) = N'{"a":1, "b":2, "c":3}'
DECLARE @vJSON2 NVARCHAR(MAX) = N'{"d":4, "e":5}'

SELECT
    @vJSON = JSON_MODIFY(@vJSON, CONCAT(N'$.', [Key]), value)
FROM
OPENJSON(@vJSON2)

SELECT @vJSON
--Output: {"a":1, "b":2, "c":3, "d":"4", "e":"5"}

Also it's not a type-safe solution, you can add a case statement to casting values according to type of OPENJSON

Discussions

SQL Server2016: Merge Operation with json source โ€“ SQLServerCentral Forums
SQL Server2016: Merge Operation with json source Forum โ€“ Learn more on SQLServerCentral More on sqlservercentral.com
๐ŸŒ sqlservercentral.com
June 9, 2017
How to merge two json arrays by property id (SQL Server) - Stack Overflow
I have two columns of json that I would like to join on id into a single select. Sample Data | a | b | +--------------... More on stackoverflow.com
๐ŸŒ stackoverflow.com
Merge 2 JSON strings in SQL Server - Stack Overflow
There is no JSON merge function in SQL Server. More on stackoverflow.com
๐ŸŒ stackoverflow.com
sql server - Combine JSON objects from multiple rows into a single object - Stack Overflow
Communities for your favorite technologies. Explore all Collectives ยท Stack Overflow for Teams is now called Stack Internal. Bring the best of human thought and AI automation together at your work More on stackoverflow.com
๐ŸŒ stackoverflow.com
November 28, 2019
Top answer
1 of 3
4

Your problem can be solved by

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

We faced similar issues trying to merge JSONs in MS SQL. We also wanted it to be recursive and allow us to define a strategy for arrays like "union", "concat" and "replace".

Our solution for JSON manipulations like merge, JSON path expressions and more is open source and available @ Github

Feel free to use, comment and contribute so we can further improve JSON methods for MS SQL.

2 of 3
3

It's Cumbersome but possible to achieve with SQL Server's built it JSON support.

First, set proper sample data (Please save us this step in your future questions):

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"
        }
    ]
}';

Then, wrap a union all query containing openjson and json_query for each one of the variables with a common table expression:

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

The result of that union all query is this:

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

Then, select the id from the first json using json_value, and add a subquery to select everything from the cte with for json path. Add another for json path and specify without_array_wrapper to the outer query:

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

The final result:

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

You can see a live demo on Db<>Fiddle

๐ŸŒ
SQLServerCentral
sqlservercentral.com โ€บ forums โ€บ topic โ€บ sql-server2016-merge-operation-with-json-source
SQL Server2016: Merge Operation with json source โ€“ SQLServerCentral Forums
June 9, 2017 - First of all, here's that query again, for those of us with screens less than 3m wide ๐Ÿ™‚ MERGE dbo.dreamlines_sails t USING ( (SELECT nid , title , nights , zone , sails_nid , arrival , departure , cabintype , catalogPrice , discountPrice , currency , discountPercentage FROM OPENROWSET(BULK 'C:\Powershell\test.json', SINGLE_CLOB)j CROSS APPLY OPENJSON(BulkColumn) WITH ( nid INT , title NVARCHAR(200) , nights INT , zone NVARCHAR(100) , sails_nid INT , arrival INT , departure INT , cabintype NVARCHAR(100) , catalogPrice INT , discountPrice INT , currency NVARCHAR(100) , discountPercentage FLOA
๐ŸŒ
TalkApex
talkapex.com โ€บ how-to-merge-json-objects-in-sql
How to merge JSON objects in SQL
November 25, 2023 - There may be instances where you ... functions using the options parameter. You can easily do this in SQL using the json_mergepatch function....
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 75254549 โ€บ merge-2-json-strings-in-sql-server
Merge 2 JSON strings in SQL Server - Stack Overflow
SELECT * FROM Original o JOIN NewData nd ON someCondition CROSS APPLY ( SELECT '{' + STRING_AGG( CONCAT( '"', ISNULL(j2.[key], j1.[key]), '":', CASE WHEN ISNULL(j2.type, j1.type) = 2 THEN '"' END, CASE WHEN ISNULL(j2.type, j1.type) = 0 THEN 'null' ELSE ISNULL(j2.value, j1.value) END, CASE WHEN ISNULL(j2.type, j1.type) = 2 THEN '"' END ), ',' ) + '}' FROM OPENJSON(o.Json) j1 FULL JOIN OPENJSON(nd.Json) j2 ON j2.[key] = j1.[key] ) merged(Json);
Find elsewhere
๐ŸŒ
LinkedIn
linkedin.com โ€บ posts โ€บ saxonchris_how-to-merge-json-objects-in-sql-activity-7165677288079007744-D7SE
Chris Saxon on LinkedIn: How to merge JSON objects in SQL
February 20, 2024 - Combine two #JSON objects with Oracle #SQL with JSON_MERGEPATCH ( jdco1, jdoc2 ) e.g. JSON_MERGEPATCH ( '{ "a1" : "v1"}', '{ "a2" : "v2" }' ) =>โ€ฆ
๐ŸŒ
Bertwagner
bertwagner.com โ€บ data with bert โ€บ posts โ€บ how to create json multi object arrays in sql server โ€บ index
How To Create Multi-Object JSON Arrays in SQL Server
December 19, 2017 - It requires using CONCAT_WS, which is available starting in SQL Server 2017 (the above solution requires STRING_AGG which is also in 2017, but it could be rewritten using FOR XML string aggregation if necessary for earlier versions) SELECT h.*, '['+ CONCAT_WS(',', (SELECT * FROM ##Car c WHERE c.HomeId = h.HomeId FOR JSON PATH, WITHOUT_ARRAY_WRAPPER), (SELECT * FROM ##Toy t WHERE t.HomeId = h.HomeId FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) ) + ']' FROM ##Home h
๐ŸŒ
Kingswaysoft
kingswaysoft.com โ€บ products โ€บ ssis-productivity-pack โ€บ help-manual โ€บ json-and-xml-processing โ€บ json-merge
Help Manual - JSON Merge - SSIS Productivity Pack
The JSON Merge Component is a transformation component used to take incoming data from upstream SSIS source components and merge them into one SSIS column based on the JSON data structure defined in the component, which can be then consumed by a downstream pipeline component.
๐ŸŒ
SQLServerCentral
sqlservercentral.com โ€บ blogs โ€บ how-to-create-multi-object-json-arrays-in-sql-server
How To Create Multi-Object JSON Arrays in SQL Server โ€“ SQLServerCentral
December 19, 2017 - It requires using CONCAT_WS, which is available starting in SQL Server 2017 (the above solution requires STRING_AGG which is also in 2017, but it could be rewritten using FOR XML string aggregation if necessary for earlier versions) SELECT h.*, '['+ CONCAT_WS(',', (SELECT * FROM ##Car c WHERE c.HomeId = h.HomeId FOR JSON PATH, WITHOUT_ARRAY_WRAPPER), (SELECT * FROM ##Toy t WHERE t.HomeId = h.HomeId FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) ) + ']' FROM ##Home h
๐ŸŒ
C# Corner
c-sharpcorner.com โ€บ forums โ€บ how-to-add-two-json-object-using-sql-server
how to Add two json object using sql server
C# Forum, C# Forums, Forums, ASP.NET Forum, VB.NET, WPF, WCF, WF, XAML, .NET 3.0, .NET 3.5, Silverlight