【问题标题】:How to insert in two tables in one time? prepared statements如何一次插入两个表?准备好的陈述
【发布时间】:2016-07-13 13:47:41
【问题描述】:

如何一次插入两个表?
我需要插入第二个表user_information 字段user_id 与第一个表user 插入返回id,我找到this answer 但我找不到如何使用params 准备好的语句

var dbQuery = 'WITH insertUser AS (
  INSERT INTO "user" (status, create_date) VALUES ($1, $2) RETURNING id
  )
  , insertUserInformation AS (
  INSERT INTO user_information (user_id, email) VALUES ($3, $4)
  )
';

yield queryPromise(dbClient, dbQuery, [status, timestamp, ??, email]);

pg

【问题讨论】:

标签: javascript sql node.js postgresql


【解决方案1】:

我不相信这可以作为一个自然的 sql 语句来完成。您必须将其包装为过程或其他机制。

【讨论】:

  • 您绝对可以在 Postgres 中的单个 SQL 语句中执行此操作,如帖子所示。也许你不能用绑定参数来做到这一点,但否则它肯定是可能的。
  • 对不起,但是帖子显示使用了两个不同的 sql 语句。我并不是说您的方法不正确,而是说它不能在 SINGLE NATURAL SQL 语句中完成。
【解决方案2】:

在 postgresql 中是不可能的。我通过创建函数并简单地使用参数执行解决了完全相同的问题。正如我在您的表结构中看到的,您没有很多属性,所以这将相对容易。

示例代码:

function.sql

CREATE OR REPLACE FUNCTION createSomething
(
    IN attr1 VARCHAR(20),
    IN attr2 VARCHAR(200)
)
RETURNS void AS $$
DECLARE userId INTEGER;
BEGIN
    INSERT INTO table1 (col1, col2) VALUES
    (
        attr1,
        attr2
    ) RETURNING id INTO userId;

    INSERT INTO table2 (user_id, col11, col2) VALUES
    (
        userId,
        col11,
        col12
    );
END;
$$ LANGUAGE plpgsql;

用法:

SELECT createSomething('value1', 'value2');

请注意,第二个插入语句将知道最近用户的 ID 并使用它。

【讨论】:

  • 感谢您的回复,您能给我举个例子吗?
  • 我编辑了答案。我不熟悉node-postgres,所以你必须自己连接这两种技术。
  • 只使用事务。如果第二个查询失败,您可以进行回滚,并且数据库仍将处于一致状态,几乎就像什么都没发生一样。
  • 默认情况下,postgresql 中的所有函数都在事务范围内运行,因此客户端代码中是否有事务无关紧要。
  • 使用@Fka 提供的事务或查询,有什么不同的性能或其他问题吗?
【解决方案3】:

使用事务。这样,要么提交所有查询,要么不提交任何查询。并且在执行所有查询之前的不完整状态对于其他进程是不可见的。

有关如何在node-postgres 中进行交易的更多信息,请访问https://github.com/brianc/node-postgres/wiki/Transactions

作为参考,最相关的部分是:

var Client = require('pg').Client;

var client = new Client(/*your connection info goes here*/);
client.connect();

var rollback = function(client) {
  //terminating a client connection will
  //automatically rollback any uncommitted transactions
  //so while it's not technically mandatory to call
  //ROLLBACK it is cleaner and more correct
  client.query('ROLLBACK', function() {
    client.end();
  });
};

client.query('BEGIN', function(err, result) {
  if(err) return rollback(client);
  client.query('INSERT INTO account(money) VALUES(100) WHERE id = $1', [1], function(err, result) {
    if(err) return rollback(client);
    client.query('INSERT INTO account(money) VALUES(-100) WHERE id = $1', [2], function(err, result) {
      if(err) return rollback(client);
      //disconnect after successful commit
      client.query('COMMIT', client.end.bind(client));
    });
  });
});

【讨论】:

  • 这是否异步工作?如果同时调用执行此代码的函数的 10,000 个实例,是否可以保证 postgres 驱动程序不会收到无效语句? (例如,一个“BEGIN”语句紧跟在另一个“BEGIN”之后)
【解决方案4】:

PostgreSQL Prepared Statements 不会让你这样做。您将不得不使用事务。

以下是您使用 ES7 语法使用 pg-promise 实现的示例:

const pgp = require('pg-promise')({
    // initialization options;
});

const db = pgp(/* your connection object or string */);

db.tx(async t => {
        const user = await t.one('INSERT INTO user(status, create_date) VALUES($1, $2) RETURNING id', [status, timestamp]);
        return t.none('INSERT INTO user_information(user_id, email) VALUES($1, $2)', [user.id, email]);
    })
    .then(() => {
        // SUCCESS;
    })
    .catch(error => {
        // ERROR;
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    相关资源
    最近更新 更多