使用 pg-promise 进行多行插入

问题描述 投票:0回答:3

我想使用单个

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 注入?

javascript node.js postgresql pg-promise
3个回答
128
投票

我是pg-promise的作者。

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

较新的方法是依赖于 helpers 命名空间,它非常灵活,并且针对性能进行了优化。

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

// 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 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 = 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
  • 多行
    INSERT
  • 单排
    UPDATE
  • 多行
    UPDATE

使用 ${} 表示法的插入是否可以防止 SQL 注入?

是的,但并不孤单。如果您要动态插入架构/表/列名称,那么使用SQL 名称非常重要,它的组合将保护您的代码免受 SQL 注入。


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


额外

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

id

A: 只需将

RETURNING id
附加到您的查询中,并使用方法 many:

执行它
const query = 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, ...]

要理解为什么我们在那里使用

+
,请参阅:pg-promise 将整数返回为字符串

更新-1

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

更新2

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

// generating a multi-row insert query inside a function:
const query = () => 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);

1
投票

尝试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')

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


-3
投票
CREATE TABLE "user"
(
    id         BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    first_name VARCHAR(255),
    last_name  VARCHAR(255),
    email      VARCHAR(255),
    password   VARCHAR(60),
    role       VARCHAR(255),
    enabled    BOOLEAN                                 NOT NULL DEFAULT FALSE,
    CONSTRAINT pk_user PRIMARY KEY (id)
);

INSERT INTO "user" (id,
                    first_name,
                    last_name,
                    email,
                    password,
                    role,
                    enabled)
VALUES (generate_series(1, 50),
       substr(gen_random_uuid()::text, 1, 10),
        substr(gen_random_uuid()::text, 1, 10),
        substr(gen_random_uuid()::text, 2, 5 )
            || '@' ||
        substr(gen_random_uuid()::text, 2, 5)
            || '.com',
        substr(gen_random_uuid()::text, 1, 10),
        (array['ADMIN', 'MANAGER', 'USER'])[floor(random() * 3 + 1)],
        (array[true, false])[floor(random() * 2 + 1)]
       );
© www.soinside.com 2019 - 2024. All rights reserved.