5

我正在尝试使用带有 pg 扩展名的 node.js(版本 0.5.4)在 postgres 数据库中进行插入或更新。

到目前为止,我有这个代码:(...)

client.query({
            text: "update users set is_active = 0, ip = $1 where id=$2",
            values: [ip,id]
        }, function(u_err, u_result){
            debug(socket_id,"update query result: ",u_result);
                debug(socket_id,"update query error: ",u_err);

                    date_now = new Date();
            var month = date_now.getMonth() + 1;

            if(!u_err){

                client.query({
                    text: 'insert into users (id,first_name,last_name,is_active,ip,date_joined) values' +
                    '($1,$2,$3,$4,$5,$6)',
                    values: [
                            result.id, 
                            result.first_name,
                            result.last_name,
                            1,
                            ip,
                            date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
                            ]
                }, function(i_err, i_result){
                    debug(socket_id,"insert query result: ",i_result);
                    debug(socket_id,"insert query error: ",i_err);
                });
            }
        });

问题是,尽管两个查询都有效,但问题总是同时运行,而不是仅在更新失败时运行插入函数。

代码输出中的调试功能类似于:

更新

Object { type="update query result: ", debug_value={...}}
home (linha 56)
Object { type="update query error: ", debug_value=null}
home (linha 56)
Object { type="insert query result: "}
home (linha 56)
Object { type="insert query error: ", debug_value={...}}

插入

Object { type="update query result: ", debug_value={...}}
home (linha 56)
Object { type="update query error: ", debug_value=null}
home (linha 56)
Object { type="insert query result: ", debug_value={...}}
home (linha 56)
Object { type="insert query error: ", debug_value=null}

** 编辑 **

来自 node-postgres 开发人员的回答:

可以检索受插入和更新影响的行数。它没有在本机绑定中完全实现,但在纯 javascript 版本中确实有效。我将在接下来的一两周内完成这项工作。同时使用纯 javascript 版本并在这里查看:

https://github.com/brianc/node-postgres/blob/master/test/integration/client/result-metadata-tests.js

** 结束编辑 **

任何人都可以帮忙吗?

4

3 回答 3

2

您的问题的直接答案是使用存储过程来执行 upsert。

http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE

这样的东西适用于 pg 模块。

client.query({
  text: "SELECT upsert($1, $2, $3, $4, $5, $6)"
  values: [ obj.id, 
            obj.first_name,
            obj.last_name,
            1,
            ip,
            date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
          ]
}, function(u_err, u_result){
  if(err) // this is a real error, handle it

  // otherwise your data is updated or inserted properly
});

当然,这假设您正在使用某种具有您需要的所有值的模型对象,即使它们没有改变。您必须将它们全部传递到 upsert 中。如果您坚持按照此处显示的方式进行操作,您可能应该在更新后检查实际的错误对象,以确定它是否因为该行已经存在或其他原因而失败(这是真正的 db 错误需要处理)。

然后,您必须处理更新失败与插入完成之间的潜在竞争条件。如果其他一些函数尝试使用相同的 id 插入,那么你就有问题了。交易对此有好处。这就是我现在所得到的。希望能帮助到你。

于 2011-11-03T07:42:13.553 回答
2

我在使用 JDBC 连接到 PG 实例时遇到了这个问题。我最终使用的解决方案是:

UPDATE table SET field='C', field2='Z' WHERE id=3;
INSERT INTO table (id, field, field2)
       SELECT 3, 'C', 'Z'
       WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3);

如果记录不存在,则更新不执行任何操作,如果记录存在,则插入不执行任何操作。它工作得很好,是一个基于 SQL 的解决方案与一个存储过程。

这是最初的问题: 在 PostgreSQL 中重复更新时插入?

于 2012-04-28T15:08:24.143 回答
0

我有一个电子元件数据库,我可以向其中添加从电子垃圾中回收或购买的新元件,我这样做的方式是:

const upsertData = (request, response) => {
  const {
    category, type, value, unit, qty,
  } = request.body;

  pool.query(`DO $$                  
    BEGIN 
        IF EXISTS
            ( SELECT 1
              FROM   elab 
              WHERE  category='${category}'
              AND    type='${type}'
              AND    value='${value}'
              AND    unit='${unit}'
            )
        THEN
            UPDATE elab 
            SET qty = qty + ${qty}
            WHERE   category='${category}'
            AND    type='${type}'
            AND     value='${value}'
            AND     unit='${unit}';
        ELSE
            INSERT INTO elab
            (category, type, value, unit, qty)
            values ('${category}', '${type}', '${value}', '${unit}', ${qty});
        END IF ;
    END
  $$ ;`, (error, results) => {
    if (error) {
      throw error;
    }
    response.status(201).send('Task completed lol');
  });
};

这样做的原因是任何条目的唯一唯一列是 ID,它会自动更新,其他列都不是唯一的,只有整个条目是例如,您可以将 100 kOhm 电阻器用作电位计或“正常”一个 - 你可以有一个不同于 100 kOhm 的电位器,所以只有整个条目是唯一的。

于 2020-02-24T11:00:54.413 回答