带有 pg-promise 的多行插入

Multi-row insert with pg-promise

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

INSERT INTO tmp(col_a,col_b) VALUES('a1','b1'),('a2','b2')...

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

[{col_a:'a1',col_b:'b1'},{col_a:'a2',col_b:'b2'}]

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

到目前为止,我只能对单个对象执行此操作:

INSERT INTO tmp(col_a,col_b) VALUES(${col_a},${col_b})

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

我是 pg-promise 的作者。

在旧版本的库中,Performance Boost 文章中的简化示例对此进行了介绍,在编写高性能数据库应用程序时仍然是一本不错的读物。

较新的方法是依赖 helpers namespace,它最终是灵活的,并且针对性能进行了优化。

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:
await db.none(query);

参见 API:ColumnSet, insert

这样的插入甚至不需要事务,因为如果一组值插入失败,none 将插入。

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

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

Are insertions using ${} notation protected against sql injection?

是的,但并不孤单。如果您要动态插入 schema/table/column 名称,使用 SQL Names 很重要,这将保护您的代码免受 SQL 注入。


相关问题:


额外内容

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

A: 只需将 RETURNING id 附加到您的查询,然后使用方法 many:

执行它
const query = pgp.helpers.insert(values, cs) + ' RETURNING id';
    
const res = await db.many(query);
//=> [{id: 1}, {id: 2}, ...]

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

const res = await db.map(query, undefined, a => +a.id);
//=> [1, 2, ...]

要了解我们为什么在那里使用 +,请参阅:

UPDATE-1

要插入大量记录,请参见Data Imports

UPDATE-2

使用v8.2.1及之后的版本,可以将静态query-generation封装成一个函数,这样就可以在query方法中生成,当query生成失败时拒绝:

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

尝试 https://github.com/datalanche/node-pg-format - 例如

var format = require('pg-format');

var myNestedArray = [['a', 1], ['b', 2]];
var sql = format('INSERT INTO t (name, age) VALUES %L', myNestedArray); 
console.log(sql); // INSERT INTO t (name, age) VALUES ('a', '1'), ('b', '2')

对象数组的工作方式类似。