简体   繁体   English

NodeJs:一对多批量插入SQL Server

[英]NodeJs : bulk insert into SQL Server one-to-many

I want to using nodejs mssql package to bulk insert data with below json:我想使用 nodejs mssql 包通过以下 json 批量插入数据:

[
    {
        "name": "Tom",
        "registerDate": "2021-10-10 00:00:00",
        "gender": 0,
        "consumeRecord":[
            {
                "date": "2021-10-11 00:00:00",
                "price": 102.5
            },
            {
                "date": "2021-10-12 00:00:00",
                "price": 200
            }
        ]
    },
    {
        "name": "Mary",
        "registerDate": "2021-06-10 00:00:00",
        "gender": 1,
        "consumeRecord":[
            {
                "date": "2021-07-11 00:00:00",
                "price": 702.5
            },
            {
                "date": "2021-12-12 00:00:00",
                "price": 98.2
            }
        ]
    }
]

I am try to mssql bulk insert for the member record with multiple consume data?我正在尝试为具有多个消费数据的成员记录进行 mssql 批量插入?

Is there anything can insert one to many with bulk insert like below.有什么东西可以像下面这样批量插入一对多。 because it seems need to insert the member table and get the id (primary key) first.因为它似乎需要先插入成员表并获取id(主键)。 Then using the id (primary key) for the consume table relation data然后将 id(主键)用于消费表关系数据

const sql = require('mssql')

// member table
const membertable = new sql.Table('Member')
table.columns.add('name', sql.Int, {nullable: false})
table.columns.add('registerDate', sql.VarChar(50), {nullable: false})
table.columns.add('gender', sql.VarChar(50), {nullable: false})

// consume record table
const consumeTable = new sql.Table('ConsumeRecord')
table.columns.add('MemberId', sql.Int, {nullable: false})
table.columns.add('Date', sql.VarChar(50), {nullable: false})
table.columns.add('price', sql.Money, {nullable: false})

// insert into member table
jsonList.forEach(data => {

    table.rows.add(data.name)
    table.rows.add(data.registerDate)
    table.rows.add(data.gender)

    consumeTable.rows.add(data.memberId) // <---- should insert member table id
    consumeTable.rows.add(data.consumeRecord.data)
    consumeTable.rows.add(data.consumeRecord.price)

    const request = new sql.Request()
    request.bulk(consumeTable , (err, result) => {

    })

})


const request = new sql.Request()
request.bulk(membertable , (err, result) => {

})

Expected Record: Member Table预期记录:成员表

id (auto increment) id(自动递增) name姓名 registerDate注册日期 gender性别
1 1 Tom汤姆 2021-10-10 00:00:00 2021-10-10 00:00:00 0 0
2 2 Mary玛丽 2021-06-10 00:00:00 2021-06-10 00:00:00 1 1

Consume Record Table消费记录表

id ID MemberId会员ID Date日期 price价钱
1 1 1 1 2021-10-10 00:00:00 2021-10-10 00:00:00 102.5 102.5
2 2 1 1 2021-10-12 00:00:00 2021-10-12 00:00:00 200 200
3 3 2 2 2021-07-11 00:00:00 2021-07-11 00:00:00 702.5 702.5
4 4 2 2 2021-12-12 00:00:00 2021-12-12 00:00:00 98.2 98.2

The best way to do this is to upload the whole thing in batch to SQL Server, and ensure that it inserts the correct foreign key.最好的方法是将整个内容批量上传到 SQL Server,并确保它插入正确的外键。

You have two options你有两个选择

  • Option 1选项1

    • Upload the main table as a Table Valued Parameter or JSON blob将主表作为表值参数或 JSON blob 上传
    • Insert with OUTPUT clause to select the inserted IDs back to the client使用OUTPUT子句插入以将插入的 ID 选择回客户端
    • Correlate those IDs back to the child table data将这些 ID 关联回子表数据
    • Bulk Insert that as well也批量插入
  • Option 2 is a bit easier: do the whole thing in SQL选项 2 更简单一点:用 SQL 完成整个事情

    • Upload everything as one big JSON blob将所有内容上传为一个大的 JSON blob
    • Insert main table with OUTPUT clause into table variable将带有OUTPUT子句的主表插入表变量
    • Insert child table, joining the IDs from the table variable插入子表,加入来自表变量的 ID
CREATE TABLE Member(
  Id int IDENTITY PRIMARY KEY,
  name varchar(50),
  registerDate datetime NOT NULL,
  gender tinyint NOT NULL
);
CREATE TABLE ConsumeRecord(
  MemberId Int NOT NULL REFERENCES Member (Id),
  Date datetime not null,
  price decimal(9,2)
);

Note the more sensible datatypes of the columns注意列的更合理的数据类型

DECLARE @ids TABLE (jsonIndex nvarchar(5) COLLATE Latin1_General_BIN2 not null, memberId int not null);

WITH Source AS (
    SELECT
      j1.[key],
      j2.*
    FROM OPENJSON(@json) j1
    CROSS APPLY OPENJSON(j1.value)
      WITH (
        name varchar(50),
        registerDate datetime,
        gender tinyint
      ) j2
)
MERGE Member m
USING Source s
  ON 1=0 -- never match
WHEN NOT MATCHED THEN
  INSERT (name, registerDate, gender)
  VALUES (s.name, s.registerDate, s.gender)
OUTPUT s.[key], inserted.ID
  INTO @ids(jsonIndex, memberId);
  
INSERT ConsumeRecord (MemberId, Date, price)
SELECT
  i.memberId,
  j2.date,
  j2.price
FROM OPENJSON(@json) j1
CROSS APPLY OPENJSON(j1.value, '$.consumeRecord')
  WITH (
    date datetime,
    price decimal(9,2)
  ) j2
JOIN @ids i ON i.jsonIndex = j1.[key];

db<>fiddle 数据库<>小提琴

Unfortunately, INSERT only allows you to OUTPUT from the inserted table, not from any non-inserted columns.不幸的是, INSERT只允许您从inserted表中OUTPUT ,而不能从任何未插入的列中输出。 So we need to hack it with a weird MERGE所以我们需要用一个奇怪的MERGE来破解它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM