将嵌套的json数组插入sql server

时间:2018-04-09 09:05:34

标签: json sql-server sql-server-2016

我在Sql server中有以下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"
               }
            ]
         }
      ]
   }
}'

表格结构如下:

enter image description here

我想在 Table2 InnerMostElement中的 Table1 InnerElement 数据中插入 FirstElement 数据 表3 中的数据。

1 个答案:

答案 0 :(得分:2)

简单的部分是第一个表,因为我们只插入一行并且它没有依赖关系:

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();

困难的部分是下一张桌子。我们需要捕获插入行的所有标识,以及还要插入到表3中的所有数据。因为OUTPUT的{​​{1}}子句仅限于在基表中输出值,我们需要使用INSERT技巧:

MERGE

如果要使用JSON主要填充表,使用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]); 个对象生成连续值(使用SEQUENCE)可能更方便,而无需将整个JSON捕获到临时值表。这将大大简化这一点,并消除对sp_sequence_get_range

的需求

最后一张表再次简单:

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;
+----+------+----------+---------+
| Id | Name | Location | Region  |
+----+------+----------+---------+
|  1 | ABC  | East US  | West US |
+----+------+----------+---------+
+----+----------+------+-----------------+--------+
| Id | Table1Id | Name |   Description   |  Type  |
+----+----------+------+-----------------+--------+
|  1 |        1 | IE1  | IE1 Description | Small  |
|  2 |        1 | IE2  | IE2 Description | Medium |
+----+----------+------+-----------------+--------+

为了完整性,请按以下步骤将其转换回JSON:

+----+----------+-----------------+--------+
| Id | Table2Id |       Key       | Value  |
+----+----------+-----------------+--------+
|  1 |        1 | Name            | IME1   |
|  2 |        1 | AnotherProperty | Value1 |
|  3 |        2 | Name            | IME2   |
|  4 |        2 | Address         | Xyz    |
|  5 |        2 | Type            | Simple |
|  6 |        2 | LastProperty    | ValueX |
+----+----------+-----------------+--------+