使用连接更新多个json节点

iibxawm4  于 2021-07-26  发布在  Java
关注(0)|答案(2)|浏览(251)

在SQLServer中,我有一个接受json参数的存储过程 @ChangeSet 如下所示。

DECLARE  @ChangeSet varchar(MAX) = 
'{
    "Acts":
    [
        {"ActId":100,"ActText":"Intro","ActNumber":1},
        {"ActId":0,  "ActText":"Beginning","ActNumber":2},
        {"ActId":0,  "ActText":"Middle","ActNumber":3},
        {"ActId":0,  "ActText":"End","ActNumber":4},
    ]
 }';

在这个过程中,我有一个 MERGE 根据表是否为 INSERT (如果 ActId0 )或者一个 UPDATE . 我想更新json @ChangeSet 变量中返回了多个pk actid INSERTEDMERGE 以便我能及时归还 OUT 参数。

ActId   Type    Action  Value       ActNumber
---------------------------------------------
100     Act     UPDATE  Intro       1
101     Act     INSERT  Beginning   2
102     Act     INSERT  Middle      3
103     Act     INSERT  End         4

我可以重新查询数据库,以json的形式输出,但我感兴趣的是找出一种使用类似 JSON_MODIFY 等,如果可能的话。
我看了各种样品,但没有发现任何类似的。有人举过好例子吗?

6kkfgxo0

6kkfgxo01#

如果我理解正确,你有两个选择:
修改 Acts json数组使用 JSON_MODIFY (但您需要sql server 2017+将变量用作路径表达式)。这种方法在 SELECT 声明,所以哟一定不要用 ORDER BY 或者 DISTINCT 在声明中。
解析输入的json,使用基于集合的方法以表的形式获得预期的结果,并使用 FOR JSON AUTO json码:

DECLARE @ChangeSet varchar(MAX) = 
'{
    "Acts":
    [
        {"ActId":100,"ActText":"Intro","ActNumber":1},
        {"ActId":0,  "ActText":"Beginning","ActNumber":2},
        {"ActId":0,  "ActText":"Middle","ActNumber":3},
        {"ActId":0,  "ActText":"End","ActNumber":4}
    ]
}';

对账单 JSON_MODIFY :

SELECT @ChangeSet = JSON_MODIFY(
   @ChangeSet,
   CONCAT('$.Acts[', j1.[key], '].ActId'), 
   v.[Id]
)   
FROM OPENJSON(@ChangeSet, '$.Acts') j1
CROSS APPLY OPENJSON(j1.[value]) WITH (ActNumber int '$.ActNumber') j2
JOIN (VALUES 
   (100, 'Act', 'UPDATE', 'Intro',     1),
   (101, 'Act', 'INSERT', 'Beginning', 2),
   (102, 'Act', 'INSERT', 'Middle',    3),
   (103, 'Act', 'INSERT', 'End',       4)
) v ([Id], [Type], [Action], [Value], [ActNumber]) ON v.[ActNumber] = j2.[ActNumber]

对账单 FOR JSON :

SELECT @ChangeSet = (
   SELECT v.[Id] AS ActId, j.ActText, j.ActNumber
   FROM OPENJSON(@ChangeSet, '$.Acts') WITH (
      ActId int '$.ActId',
      ActText varchar(50) '$.ActText',
      ActNumber int '$.ActNumber'
   ) j
   JOIN (VALUES 
      (100, 'Act', 'UPDATE', 'Intro',     1),
      (101, 'Act', 'INSERT', 'Beginning', 2),
      (102, 'Act', 'INSERT', 'Middle',    3),
      (103, 'Act', 'INSERT', 'End',       4)
   ) v ([Id], [Type], [Action], [Value], [ActNumber]) ON v.[ActNumber] = j.[ActNumber]
   FOR JSON AUTO, ROOT ('Acts')
)

结果:

{
    "Acts":
    [
        {"ActId":100, "ActText":"Intro", "ActNumber":1},
        {"ActId":101, "ActText":"Beginning", "ActNumber":2},
        {"ActId":102, "ActText":"Middle", "ActNumber":3},
        {"ActId":103, "ActText":"End", "ActNumber":4}
    ]
}
e1xvtsh3

e1xvtsh32#

为了完整地回答这个问题,下面是一个完成的例程,它获取merge语句的输出,将其插入temp表变量,然后用新插入的actid主键更新输入json,这样就可以由procedure out变量返回。

-- SQL 2017+ REQUIRED

DECLARE @ActActions  table( [ActId] int, [Action] varchar(30),
                     [Value] nvarchar(max), [ActNumber] int );

---------------------------------------------------------------------------------

OUTPUT   COALESCE (INSERTED.ActId, DELETED.ActId), $action, 
         COALESCE (INSERTED.ActText, DELETED.ActText),
         COALESCE (INSERTED.ActNumber, DELETED.ActNumber)
INTO    @ActActions;   -- Required semi-colon at end of MERGE

---------------------------------------------------------------------------------

SELECT  @ChangeSetJson = JSON_QUERY(JSON_MODIFY( 
        @ChangeSetJson, '$.Acts[' + j1.[key] + '].ActId', a.[ActId] )  )
FROM    OPENJSON(@ChangeSetJson, '$.Acts') j1 CROSS APPLY 
        OPENJSON(j1.[value])
        WITH (ActNumber int '$.ActNumber') j2 INNER JOIN
        @ActActions a
            ON a.[ActNumber] = j2.[ActNumber]
WHERE  a.[Action] = 'INSERT'

相关问题