我有一个表在一列中存储json。我想通过合并另一个json来更新json值。
类似的东西:
insert into mytable
values ('{ "a": "b" ')
update mytable
set jsonColumn = JSON_MERGE(jsonColumn, '{ "c": 2 }')
这应该导致json像这样:
{ "a": "b", "c": 2 }
不幸的是,没有这样的JSON_MERGE
函数,而JSON_MODIFY只允许我逐个修改列。我有太多这些,包括嵌套属性。
我基本上都在搜索等同于postgres || concatenation operator的内容。
答案 0 :(得分:3)
在Sql Server 2016中,无法在JSON_MODIFY
中将变量用作json路径,因此我不确定是否有解决此问题的简便方法。
如果您拥有Sql Server 2017,则似乎有可能。
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;
笔记夫妇:
CONCAT
会有一个后备; JSON_QUERY
函数,以便正确插入json; SELECT
语句中分配了变量,则可以在赋值语句中使用变量的先前值; 更新:我添加了一些改进的版本,可以更好地处理不同类型的值:
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
答案 1 :(得分:0)
在JSON_MODIFY中有追加概念,但这取决于标记名称。请参阅下面的示例。如果你有标签名称,那么它可以工作,否则不行。阅读https://docs.microsoft.com/en-us/sql/t-sql/functions/json-modify-transact-sql的更多内容。另请注意,在某个时间点,您可以附加单个值
PRINT 'EXAMPLE 1
'
DECLARE @j NVARCHAR(MAX)
SET @j = '{"k" : ["a","b"] }'
PRINT @J
SET @J=JSON_MODIFY(JSON_MODIFY(@j,'append $.k','c'),'append $.k','2')
PRINT @J
GO
PRINT '
EXAMPLE 2
'
DECLARE @j NVARCHAR(MAX)
SET @j = '{"a":"b"}'
PRINT @J
SET @J=JSON_MODIFY(@J,'append $','c:2')
PRINT @J
GO
输出
EXAMPLE 1
{"k" : ["a","b"] }
{"k" : ["a","b","c","2"] }
EXAMPLE 2
{"a":"b"}
{"a":"b"}
答案 2 :(得分:0)
您可以执行与该代码类似的操作:
DECLARE @json1 nvarchar(max),
@json2 nvarchar(max)
DECLARE @result AS nvarchar(max)
SET @json1 = N'{"a": "1", "c": "3"}'
SET @json2 = N'{"b": "2"}'
SELECT
@result = COALESCE(@result + ', ', '') + '"' + [key] + '":"' + value + '"'
FROM (SELECT
[key],
value
FROM OPENJSON(@json1)
UNION ALL
SELECT
[key],
value
FROM OPENJSON(@json2)) AS x
SET @result = '{' + @result + '}'
PRINT @result
@result是
{"a":"1", "c":"3", "b":"2"}
答案 3 :(得分:0)
我参加聚会有点晚了,但是现在我遇到了类似的情况。我根据this问题提出了一个解决方案,该问题将合并顶级JSON项目。
此操作的一些示例:
{"a":1} + {"B":2} = {"a":1,"B":2}
{"x":true,"y":{"a":"b","c":"d"}} + {"y":{"a":"z"}} = {"x":true,"y":{"a":"z"}}
此版本不会向下钻取以合并子项(例如,在我的第二个示例中,它不会保留[“ y”] [“ c”]索引)。我以为可以对此进行增强,但这是一个快速的概念验证版本,我不需要担心出于我的目的需要进行此类更新。
内容:
--- Merge the top-level items of two JSON object strings into one JSON
--- based off of: https://stackoverflow.com/questions/47489030/generate-a-json-string-containing-the-differences-in-two-other-json-strings-usin
DECLARE @jsonA NVARCHAR(MAX) = '{"CommonValue":"OriginalThing", "OldValue": "A", "ComplexValue": {"InnerValue": "ABC"}}'
,@jsonB NVARCHAR(MAX) = '{"CommonValue":"ChangedThing", "NewValue": "B", "Number": 22}'
,@result NVARCHAR(MAX) = ''
--- Catalog of differences.
DECLARE @JsonDiff TABLE
(
OldKey CHAR(128),
OldValue NVARCHAR(MAX),
OldType CHAR(1),
NewKey CHAR(128),
NewValue NVARCHAR(MAX),
NewType CHAR(1)
)
--- Temporary table for output rows.
--- The table could probably clipped out for production stuff.
--- For proof-of-concept, it's useful for querying results
--- before building the JSON string.
DECLARE @JsonData TABLE
(
NewKey CHAR(128),
NewValue NVARCHAR(MAX),
NewType CHAR(1)
)
;WITH DSA AS
(
SELECT *
FROM OPENJSON(@jsonA)
)
,DSB AS
(
SELECT *
FROM OPENJSON(@jsonB)
)
INSERT INTO @JsonDiff (OldKey, OldValue, OldType, NewKey, NewValue, NewType)
SELECT a.[Key] aKey, a.[Value] aValue, a.[Type] aType, b.[Key] bKey, b.[Value] bValue, b.[Type] bType
FROM DSA A
FULL OUTER JOIN DSB B ON A.[key] = B.[key]
INSERT INTO @JsonData (NewKey, NewValue, NewType)
SELECT OldKey as k, OldValue as v, OldType as t
FROM @JsonDiff
WHERE OldKey IS NOT NULL AND NewKey IS NULL
UNION
SELECT NewKey as k, NewValue as v, NewType as t
FROM @JsonDiff
WHERE NewKey IS NOT NULL
--- a few queries for display purposes
--- select * FROM @JsonDiff
select NewKey, NewValue FROM @JsonData
SELECT @result += CONCAT ( '"', TRIM([NewKey]), '":'
,IIF([NewType] = 1, CONCAT('"', [NewValue], '"'), [NewValue]) -- If the item is a string, then add quotes.
,','
)
FROM @JsonData
--- Print the JSON
SELECT CONCAT('{', LEFT(@result, LEN(@result) - 1), '}')
编辑:以下是最后一点的简化版本,无需使用@JsonData
:
SELECT @result += CONCAT ( '"', TRIM([k]), '":'
,IIF([t] = 1, CONCAT('"', [v], '"'), [v]) -- If the item is a string, then add quotes.
,','
)
FROM
(
SELECT OldKey as k, OldValue as v, OldType as t
FROM @JsonDiff
WHERE OldKey IS NOT NULL AND NewKey IS NULL
UNION
SELECT NewKey as k, NewValue as v, NewType as t
FROM @JsonDiff
WHERE NewKey IS NOT NULL
) as mid
--- Print the JSON
SELECT CONCAT('{', LEFT(@result, LEN(@result) - 1), '}')
答案 4 :(得分:0)
聚会也有点晚,但是我们在尝试在MS SQL中合并JSON时遇到了类似的问题。我们还希望它具有递归性,并允许我们为诸如“联合”,“ concat”和“替换”之类的数组定义策略。
我们针对merge,JSON path expressions等JSON操作的解决方案变成了开源,现在可以在Github上使用
随时使用,评论和贡献,因此我们可以进一步改进MS SQL的JSON方法。
答案 5 :(得分:0)
也可以看看:
SELECT (
SELECT
(
SELECT ID AS "test.id"
FROM [Table1]
FOR JSON AUTO
) AS 'test1',
'id' AS 'test2'
FROM test2
FOR JSON AUTO
) AS JSON