将嵌套的json数组插入sql server中的多个表中 [英] Insert nested json array into multiple tables in sql server

查看:62
本文介绍了将嵌套的json数组插入sql server中的多个表中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Sql 服务器中有以下 Json 对象.我想将此数据插入到具有它们的关系(即外键)的多个表中:

I have following Json Object in Sql server. I want to insert this data into multiple tables with their relation (i.e. foreign key):

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

表结构附在这里:

我想在Table1 中插入FirstElement 数据,在Table2InnerMostElement 中插入InnerElement 数据Table3 中的数据.

I want to insert the FirstElement data in Table1, InnerElement data in Table2 and InnerMostElement data in Table3.

推荐答案

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

The easy part is the first table, because we're only inserting one row and it has no dependencies:

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 的数据.因为 INSERTOUTPUT 子句仅限于输出值仅在基表中,我们需要使用 MERGE 技巧:

The hard part is the next table. We need to capture all the identities of the inserted rows, but also all the data yet to be inserted into table 3. Because the OUTPUT clause of INSERT is restricted to outputting values in the base table only, we need to use MERGE trickery:

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

如果主要使用 JSON 填充表,使用 SEQUENCE 对象生成连续值(使用 sp_sequence_get_range)可能更方便,而无需捕获将整个 JSON 放入临时表中.这将大大简化这一过程并消除对 MERGE 的需求.

If the tables are to be primarily filled using JSON, it may be more convenient to use SEQUENCE objects to generate consecutive values (using sp_sequence_get_range) without the need to capture the whole JSON into a temporary table. That would greatly simplify this and remove the need for 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;

事务在逻辑上是确保该对象完全插入或根本不插入的必要条件.

The transaction is logically necessary to ensure this object is entirely inserted, or not at all.

最终输出:

+----+------+----------+---------+
| 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 |
+----+----------+------+-----------------+--------+

+----+----------+-----------------+--------+
| 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 |
+----+----------+-----------------+--------+

为了完整起见,您可以通过以下方式将其转回 JSON:

For completeness, here's how you'd turn that back into 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;

这篇关于将嵌套的json数组插入sql server中的多个表中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆