在node.js中导入sql文件并针对PostgreSQL执行

wfauudbj  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(5)|浏览(112)

我正在寻找一种有效的方法来获取一个原始的sql文件,并在postgres数据库中同步执行,类似于通过psql运行它。
我有一个sql文件,它创建所有数据库,导入数据等。我需要使用node.js执行此操作,但找不到任何自动执行此操作的模块。对于node.js应用程序本身,我们使用node-postgres('pg'),knex.js和bookshelf.js。我认为pg最适合此操作。
我能想到的一个替代方案是读取整个文件,用空格分割它,用空格替换换行符,修剪任何重复的空格,然后以顺序执行的方式将其逐个送入pg,如果这真的是最有效的方法,而且还没有库可以解决这个问题,我有点惊讶。本身就有点挑战性,我可能会不小心把它捣碎。
提前澄清一下:

  • 无法使用psql,因为它未安装在目标计算机上
  • 我选择以SQL原生形式开发SQL语句并对其进行源代码控制,因为DBA使用和操作它要容易得多
bvjveswy

bvjveswy1#

在传递给client.query时,您可以使用一个分隔符来分隔后续查询
这是可行的:

var pg = require('pg');

pg.connect('postgres://test:test@localhost/test', function(err, client, done){
        client.query('CREATE TABLE test (test VARCHAR(255)); INSERT INTO test VALUES(\'test\') ');
        done();
});

字符串
因此,这也起作用:

var pg = require('pg');
var fs = require('fs');

var sql = fs.readFileSync('init_database.sql').toString();

pg.connect('postgres://test:test@localhost/test', function(err, client, done){
    if(err){
        console.log('error: ', err);
        process.exit(1);
    }
    client.query(sql, function(err, result){
        done();
        if(err){
            console.log('error: ', err);
            process.exit(1);
        }
        process.exit(0);
    });
});

4xy9mtcn

4xy9mtcn2#

我已经写了下面的函数,它适用于我的情况。如果没有的话,它会简单得多:

  • 使用batch管理并发
  • 需要考虑棘手的PostgreSQL COPY案例

代码片段:

function processSQLFile(fileName) {

  // Extract SQL queries from files. Assumes no ';' in the fileNames
  var queries = fs.readFileSync(fileName).toString()
    .replace(/(\r\n|\n|\r)/gm," ") // remove newlines
    .replace(/\s+/g, ' ') // excess white space
    .split(";") // split into all statements
    .map(Function.prototype.call, String.prototype.trim)
    .filter(function(el) {return el.length != 0}); // remove any empty ones

  // Execute each SQL query sequentially
  queries.forEach(function(query) {
    batch.push(function(done) {
      if (query.indexOf("COPY") === 0) { // COPY - needs special treatment
        var regexp = /COPY\ (.*)\ FROM\ (.*)\ DELIMITERS/gmi;
        var matches = regexp.exec(query);
        var table = matches[1];
        var fileName = matches[2];
        var copyString = "COPY " + table + " FROM STDIN DELIMITERS ',' CSV HEADER";
        var stream = client.copyFrom(copyString);
        stream.on('close', function () {
          done();
        });
        var csvFile = __dirname + '/' + fileName;
        var str = fs.readFileSync(csvFile);
        stream.write(str);
        stream.end();
      } else { // Other queries don't need special treatment
        client.query(query, function(result) {
          done();
        });
      }
    });
  });
}

字符串
请注意,如果您在任何地方使用SQL语句,除了终止SQL语句之外,这将失败。

ybzsozfc

ybzsozfc3#

@databases/pg客户端支持立即运行SQL文件:

const createPool = require('@databases/pg');
const {sql} = require('@databases/pg');

const db = createPool();

db.query(sql.file('my-file.sql')).catch(ex => {
  console.error(ex);
  process.exitCode = 1;
}).then(() => db.dispose());

字符串
它还支持在对db.query的单个调用中包含多个语句:

const createPool = require('@databases/pg');
const {sql} = require('@databases/pg');

const db = createPool();

db.query(sql`
  INSERT INTO users (name) VALUES (${'Forbes'});
  SELECT * FROM users;
`)).then(
  results => console.log(results)
).catch(ex => {
  console.error(ex);
  process.exitCode = 1;
}).then(() => db.dispose());


在此范例中,会依序执行每个陈述式,并传回最后一个陈述式的结果。

yk9xbfzb

yk9xbfzb4#

下面的代码,它只是将一个文件读入一个字符串,然后使用query运行它,似乎对我有用:

const { Pool } = require("pg");
const pool = new Pool({ host, port, user, password, database });
dbClient = await pool.connect();

var sql = fs.readFileSync("/path/to/file.sql", "utf8");
await dbClient.query(sql);

字符串
如果它也有帮助,这里是进一步的代码,以按字母顺序运行目录中的所有“*.sql”文件:

const pathWithSqlFiles = "/path/to/sqldir";
const filenames = fs
  .readdirSync(pathWithSqlFiles, { withFileTypes: true })
  .filter((item) => !item.isDirectory() && item.name.toLowerCase().endsWith(".sql"))
  .map((item) => item.name);
for (const filename of filenames) {
  var sql = fs.readFileSync(`${pathWithSqlFiles}/${filename}`, "utf8");
  await dbClient.query(sql);
}


(Don不要忘记在这之后的某个时候使用await dbClient.end()关闭客户端连接)。

db2dz4w8

db2dz4w85#

有很多方法可以通过SQL文件导入数据库,最简单快捷的方法是在保存文件的cmd中运行此命令:

psql -h localhost -U postgres -d myDataBase -a -f myFile.sql

字符串
或者你可以通过node.js读取和解析文件,然后运行它,但这需要时间。

function processSQLFile(fileName) {

  // Extract SQL queries from files. Assumes no ';' in the fileNames
  var queries = fs.readFileSync(fileName).toString()
    .replace(/(\r\n|\n|\r)/gm," ") // remove newlines
    .replace(/\s+/g, ' ') // excess white space
    .split(";") // split into all statements
    .map(Function.prototype.call, String.prototype.trim)
    .filter(function(el) {return el.length != 0}); // remove any empty ones

  // Execute each SQL query sequentially
  queries.forEach(function(query) {
    batch.push(function(done) {
      if (query.indexOf("COPY") === 0) { // COPY - needs special treatment
        var regexp = /COPY\ (.*)\ FROM\ (.*)\ DELIMITERS/gmi;
        var matches = regexp.exec(query);
        var table = matches[1];
        var fileName = matches[2];
        var copyString = "COPY " + table + " FROM STDIN DELIMITERS ',' CSV HEADER";
        var stream = client.copyFrom(copyString);
        stream.on('close', function () {
          done();
        });
        var csvFile = __dirname + '/' + fileName;
        var str = fs.readFileSync(csvFile);
        stream.write(str);
        stream.end();
      } else { // Other queries don't need special treatment
        client.query(query, function(result) {
          done();
        });
      }
    });
  });
}

相关问题