【问题标题】:Inserting multiple rows into SQL Server from Node.js从 Node.js 将多行插入 SQL Server
【发布时间】:2020-11-09 17:22:24
【问题描述】:

我正在开发一个项目,该项目将从 node.js 程序上传一些记录到 SQL Server。现在,这是我的方法(在异步函数中):

con = await sql.connect(`mssql://${SQL.user}:${SQL.password}@${SQL.server}/${SQL.database}?encrypt=true`);
for (r of RECORDS) {
        columns = `([column1], [column2], [column3])`;
        values = `(@col1, @col2, @col3)`;
        await con
            .request()
            .input("col1", sql.Int, r.col1)
            .input("col2", sql.VarChar, r.col2)
            .input("col3", sql.VarChar, r.col3)
            .query(`INSERT INTO [dbo].[table1] ${columns} VALUES ${values}`);
}

其中 records 是表单中的对象数组:

RECORDS = [
    { col1: 1, col2: "asd", col3: "A" },
    { col1: 2, col2: "qwerty", col3: "B" },
    // ...
];

此代码有效,但是,我觉得它根本没有效率。我上传了大约 4k 条记录,大约需要 10 分钟,看起来不太好。

我相信如果我可以创建单个查询 - 而不是将单个插入包装在 for 循环中 - 使用所有记录值会更快,而且我知道在 SQL 中可以使用语法:

INSERT INTO table1 (column1, column2, column3) VALUES (1, "asd", "A"), (2, "qwerty", "B"), (...);

但是,我无法从 mssql 模块中找到任何有关如何准备参数化输入以在单个事务中完成所有操作的文档。

谁能引导我走向正确的方向?

提前致谢。

【问题讨论】:

  • 好的,我已经尝试按照您发送给我的链接进行操作,但我遇到了一些错误。 VarChar(max) 字段有一个复杂性,我认为它是用 {length: infinity} 整理的,但我有一些列类型错误。让我给它更多时间再回复你
  • 没关系,这是我的错,这个成功了,谢谢华金

标签: node.js sql-server tedious node-mssql


【解决方案1】:

正如@JoaquinAlvarez 所指出的,应使用此处回复的批量插入:Bulk inserting with Node mssql package

对于我来说,代码是这样的:

return await sql.connect(`mssql://${SQL.user}:${SQL.password}@${SQL.server}/${SQL.database}?encrypt=true`).then(() => {
    table = new sql.Table("table1");
    table.create = true;
    table.columns.add("column1", sql.Int, { nullable: false });
    table.columns.add("column2", sql.VarChar, { length: Infinity, nullable: true });
    table.columns.add("column3", sql.VarChar(250), { nullable: true });

    // add here rows to insert into the table
    for (r of RECORDS) {
        table.rows.add(r.col1, r.col2, r.col3);
    }

    return new sql.Request().bulk(table);
});

SQL 数据类型必须(显然)匹配现有表table1 的列类型。注意 column2 的情况,它是 SQL 中定义为 varchar(max) 的列。

感谢华金!我的时间从 10 分钟显着下降到几秒钟

【讨论】:

    【解决方案2】:

    另外,与批量插入非常相似,您可以使用表值参数。

    sql.connect("mssql://${SQL.user}:${SQL.password}@${SQL.server}/${SQL.database}?encrypt=true")
      .then(() => {
        const table = new sql.Table();
        table.columns.add('col1', sql.Int);
        table.columns.add('col2', sql.VarChar(20));
        table.columns.add('col3', sql.VarChar(20));
    
        // add data
        table.rows.add(1, 'asd', 'A');
        table.rows.add(2, 'qwerty', 'B');
    
        const request = new sql.Request();
        request.input('table1', table);  
    
        request.execute('procMyProcedure', function (err, recordsets, returnValue) {  
           console.dir(JSON.stringify(recordsets[0][0]));  
           res.end(JSON.stringify(recordsets[0][0]));  
        });  
      });
    

    然后对于 SQL 端,创建一个用户定义的表类型

    CREATE TYPE typeMyType AS TABLE
    (
       Col1 int,
       Col2 varchar(20),
       Col3 varchar(20)
    )
    

    然后在存储过程中使用这个

    CREATE PROCEDURE procMyProcedure
       @table1 typeMyType READONLY
    AS
    BEGIN
       INSERT INTO table1 (Col1, Col2, Col3)
       SELECT Col1, Col2, Col3
       FROM @MyRecords
    END
    

    这使您可以更好地控制数据,并让您在实际插入之前对 sql 中的数据进行更多操作。

    【讨论】:

    • 感谢您的回复,我选择了 Joaquin 的方法,但我赞成您的回答!谢谢!
    猜你喜欢
    • 2019-05-11
    • 2014-08-19
    • 2020-01-28
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    相关资源
    最近更新 更多