Nam*_*yal 1 sql-server json sql-server-2016
我在 Sql 服务器中有以下 Json 对象。我想将此数据插入多个表及其关系(即外键):
DECLARE @JsonObject NVARCHAR(MAX) = N'{
"FirstElement":{
"Name":"ABC",
"Location":"East US",
"Region":"West US",
"InnerElement":[
{
"Name":"IE1",
"Description":"IE1 Description",
"Type":"Small",
"InnerMostElement":[
{
"Key":"Name",
"Value":"IME1"
},
{
"Key":"AnotherProperty",
"Value":"Value1"
}
]
},
{
"Name":"IE2",
"Description":"IE2 Description",
"Type":"Medium",
"InnerMostElement":[
{
"Key":"Name",
"Value":"IME2"
},
{
"Key":"Address",
"Value":"Xyz"
},
{
"Key":"Type",
"Value":"Simple"
},
{
"Key":"LastProperty",
"Value":"ValueX"
}
]
}
]
}
}'
Run Code Online (Sandbox Code Playgroud)
表结构附在这里:
我要插入FirstElement在数据表1,InnerElement在数据表2和InnerMostElement数据表3。
最简单的部分是第一个表,因为我们只插入一行并且它没有依赖项:
BEGIN TRANSACTION;
INSERT Table1([Name], [Location], [Region])
SELECT [Name], [Location], [Region]
FROM OPENJSON(@JsonObject, '$.FirstElement')
WITH (
[Name] VARCHAR(100),
[Location] VARCHAR(100),
[Region] VARCHAR(100)
);
DECLARE @Table1Id INT = SCOPE_IDENTITY();
Run Code Online (Sandbox Code Playgroud)
困难的部分是下一张桌子。我们需要捕获插入行的所有标识,还要捕获所有尚未插入表 3 的数据。 因为 的OUTPUT子句INSERT仅限于输出基表中的值,所以我们需要使用MERGE技巧:
DECLARE @Table3Input TABLE([Table2Id] INT, [InnerMostElement] NVARCHAR(MAX));
MERGE Table2
USING (
SELECT [Name], [Description], [Type], [InnerMostElement]
FROM OPENJSON(@JsonObject, '$.FirstElement.InnerElement')
WITH (
[Name] VARCHAR(100),
[Description] VARCHAR(100),
[Type] VARCHAR(100),
[InnerMostElement] NVARCHAR(MAX) AS JSON
)
) AS J
ON 1 = 0 -- Always INSERT
WHEN NOT MATCHED THEN
INSERT([Table1Id], [Name], [Description], [Type])
VALUES (@Table1Id, J.[Name], J.[Description], J.[Type])
OUTPUT inserted.Id, J.[InnerMostElement]
INTO @Table3Input([Table2Id], [InnerMostElement]);
Run Code Online (Sandbox Code Playgroud)
如果主要使用 JSON 填充表,则使用SEQUENCE对象生成连续值(使用sp_sequence_get_range)可能更方便,而无需将整个 JSON 捕获到临时表中。这将大大简化这一过程并消除对MERGE.
最后一个表又简单了:
INSERT Table3([Table2Id], [Key], [Value])
SELECT [Table2Id], KV.[Key], KV.[Value]
FROM @Table3Input CROSS APPLY (
SELECT [Key], [Value]
FROM OPENJSON([InnerMostElement])
WITH (
[Key] VARCHAR(100),
[Value] VARCHAR(100)
)
) AS KV;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
该事务在逻辑上是确保该对象被完全插入或根本不插入的必要条件。
最终输出:
BEGIN TRANSACTION;
INSERT Table1([Name], [Location], [Region])
SELECT [Name], [Location], [Region]
FROM OPENJSON(@JsonObject, '$.FirstElement')
WITH (
[Name] VARCHAR(100),
[Location] VARCHAR(100),
[Region] VARCHAR(100)
);
DECLARE @Table1Id INT = SCOPE_IDENTITY();
Run Code Online (Sandbox Code Playgroud)
DECLARE @Table3Input TABLE([Table2Id] INT, [InnerMostElement] NVARCHAR(MAX));
MERGE Table2
USING (
SELECT [Name], [Description], [Type], [InnerMostElement]
FROM OPENJSON(@JsonObject, '$.FirstElement.InnerElement')
WITH (
[Name] VARCHAR(100),
[Description] VARCHAR(100),
[Type] VARCHAR(100),
[InnerMostElement] NVARCHAR(MAX) AS JSON
)
) AS J
ON 1 = 0 -- Always INSERT
WHEN NOT MATCHED THEN
INSERT([Table1Id], [Name], [Description], [Type])
VALUES (@Table1Id, J.[Name], J.[Description], J.[Type])
OUTPUT inserted.Id, J.[InnerMostElement]
INTO @Table3Input([Table2Id], [InnerMostElement]);
Run Code Online (Sandbox Code Playgroud)
INSERT Table3([Table2Id], [Key], [Value])
SELECT [Table2Id], KV.[Key], KV.[Value]
FROM @Table3Input CROSS APPLY (
SELECT [Key], [Value]
FROM OPENJSON([InnerMostElement])
WITH (
[Key] VARCHAR(100),
[Value] VARCHAR(100)
)
) AS KV;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
为了完整起见,您可以通过以下方式将其转回 JSON:
SELECT
[Name] AS 'FirstElement.Name',
[Location] AS 'FirstElement.Location',
[Region] AS 'FirstElement.Region',
(
SELECT
[Name],
[Description],
[Type],
(
SELECT
[Key],
[Value]
FROM Table3
WHERE Table3.Table2Id = Table2.Id
FOR JSON PATH
) AS 'InnerMostElement'
FROM Table2
WHERE Table2.Table1Id = Table1.Id
FOR JSON PATH
) AS 'FirstElement.InnerElement'
FROM Table1
FOR JSON PATH;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6428 次 |
| 最近记录: |