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

新手上路,请多包涵

我正在寻找一种有效的方法来获取原始 sql 文件并使其与 postgres 数据库同步执行,类似于通过 psql 运行它。

我有一个创建所有数据库、导入数据等的 sql 文件。我需要使用 node.js 执行此操作,但找不到任何自动执行此操作的模块。对于 node.js 应用程序本身,我们使用 node-postgres (‘pg’)、knex.js 和 bookshelf.js。我认为虽然 pg 最适合这个。

我能想到的另一种选择是读取完整文件,用分号拆分,用空格替换换行符,修剪任何重复的空格,然后以顺序执行而不是异步执行的方式将其逐个输入 pg。如果这确实是最有效的方法,并且如果还没有库可以解决这个问题,我会感到有点惊讶。我有点犹豫要不要跳进去,因为 SQL 语法本身可能有点挑战性,我可能会不小心把它混在一起。

提前说明几点:

  • psql 无法使用,因为它没有安装在目标机器上
  • 我选择以 sql 原生形式开发和源代码控制 sql 语句,因为 DBA 使用和操作它要容易得多

原文由 rgareth 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 637
2 个回答

我编写了以下适用 于我的 情况的函数。如果不是因为它会更简单:

  • 使用 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 语句之外的任何地方使用分号,这将失败。

原文由 rgareth 发布,翻译遵循 CC BY-SA 3.0 许可协议

传递给 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);
    });
});

原文由 OhJeez 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题