具有pg-promise的多行插入

Bom*_*maz 28 postgresql node.js pg-promise

我想用一个INSERT查询插入多行,例如:

INSERT INTO tmp(col_a,col_b) VALUES('a1','b1'),('a2','b2')...
Run Code Online (Sandbox Code Playgroud)

有没有办法轻松地做到这一点,最好是这样的对象数组:

[{col_a:'a1',col_b:'b1'},{col_a:'a2',col_b:'b2'}]
Run Code Online (Sandbox Code Playgroud)

我可能最终在一个块中有500条记录,因此运行多个查询是不可取的.

到目前为止,我只能为一个对象做到这一点:

INSERT INTO tmp(col_a,col_b) VALUES(${col_a},${col_b})
Run Code Online (Sandbox Code Playgroud)

作为一个附带问题:使用${}符号的插入是否可以防止SQL注入?

vit*_*y-t 61

我是pg-promise的作者.

在旧版本的库中,性能提升文章中的简化示例涵盖了这一点,在编写高性能数据库应用程序时,这仍然是一个重要的读物.

较新的方法是依赖于helper命名空间,该命名空间最终是灵活的,并且针对性能进行了高度优化.

const pgp = require('pg-promise')({
    /* initialization options */
    capSQL: true // capitalize all generated SQL
});
const db = pgp(/*connection*/);

// our set of columns, to be created only once (statically), and then reused,
// to let it cache up its formatting templates for high performance:
const cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tmp'});

// data input values:
const values = [{col_a: 'a1', col_b: 'b1'}, {col_a: 'a2', col_b: 'b2'}];

// generating a multi-row insert query:
const query = pgp.helpers.insert(values, cs);
//=> INSERT INTO "tmp"("col_a","col_b") VALUES('a1','b1'),('a2','b2')

// executing the query:
db.none(query);
    .then(data => {
        // success, data = null
    })
    .catch(error => {
        // error;
    });
Run Code Online (Sandbox Code Playgroud)

请参阅API:ColumnSet,insert.

这样的插入甚至不需要事务,因为如果一组值无法插入,则不会插入任何值.

您可以使用相同的方法生成以下任何查询:

  • 单排 INSERT
  • 多行 INSERT
  • 单排 UPDATE
  • 多行 UPDATE

使用$ {}表示法的插入是否受到sql注入的保护?

是的,但并不孤单.如果要动态插入模式/表/列名称,则使用SQL名称非常重要,它们将保护您的代码免受SQL注入的影响.


相关问题:Node.js中的PostgreSQL多行更新


演员

问:如何同时获取id每条新记录?

答:只需附加RETURNING id到您的查询,并使用多种方法执行它:

const query = pgp.helpers.insert(values, cs) + 'RETURNING id';

const res = await db.many(query);
//=> [{id: 1}, {id: 2}, ...]
Run Code Online (Sandbox Code Playgroud)

甚至更好,获取id-s,并使用方法映射将结果转换为整数数组:

const res = await db.map(query, [], a => +a.id);
//=> [1, 2, ...]
Run Code Online (Sandbox Code Playgroud)

要理解我们在+那里使用的原因,请参阅:pg-promise将整数作为字符串返回.

UPDATE-1

要插入大量记录,请参阅数据导入.

UPDATE-2

使用v8.2.1及更高版本,可以将静态查询生成包装到函数中,因此可以在查询方法中生成,以便在查询生成失败时拒绝:

// generating a multi-row insert query inside a function:
const query = () => pgp.helpers.insert(values, cs);
//=> INSERT INTO "tmp"("col_a","col_b") VALUES('a1','b1'),('a2','b2')

// executing the query as a function that generates the query:
await db.none(query);
Run Code Online (Sandbox Code Playgroud)

  • @IvanSchwarz当然,只需将`RETURNING id`附加到生成的查询中,然后用`many`而不是`none`执行它. (4认同)
  • @ vitaly-t:很好的回答,谢谢!有没有办法在同一个查询中返回新插入记录的ID(或其他信息)?您在[使用pg-promise插入多个记录](http://stackoverflow.com/questions/36233566/inserting-multiple-records-with-pg-promise)中为批量查询提出了类似的建议. (2认同)
  • @vitaly-t 是否可以实现批量更新插入助手?基本上是这样的:插入表(col1,col2)值('a1','b1'),('a2','b2')ON CONFLICT(col1)DO UPDATE SET(col1,col2)=(' a1','b1'),('a2','b2') (2认同)