一尘不染

等效于ON CONFLICT DO NOTHING FOR UPDATE postgres

sql

如果更新的版本不违反主键约束,我想更新我的postgres数据库中的行。如果可以的话,我想保留该行。

假设表上有主键col1, col2, col3,如果我运行这样的查询:

UPDATE table SET (col1, col2) = ('A', 'B') 
      WHERE col1='D' AND col2='E';

查询将失败,并且如果存在两个条目,我将得到重复的键错误:

'A', 'B', 'C'
'D', 'E', 'C'

col3在现有行和要更新的行之间是相同的。

如果我INSERTON CONFLICT DO NOTHING查看行,则可以使用,但找不到的实现UPDATE。是否存在等价物?


阅读 138

收藏
2021-05-16

共1个答案

一尘不染

AFAIK,没有这样的等效项。

假设您正在开发一个连接到postgresql数据库的应用程序,那么在您的问题上下文中,需要牢记一些注意事项:

  • 这可能是反直觉的,但你应该考虑由DB被抛出的错误 东西。
    这仅仅是获取状态,并不意味着应用程序崩溃。

  • 对于插入,有另一种选择的操作on conflict(更新或不执行任何操作),因此具有让您决定的语法是有意义的。
    对于更新,您唯一可以做的就是……什么都没有。
    那么,既然没有选择,SQL为什么会让您要求做特定的事情呢?请记住,数据库报告错误是 很好的 ,所以让数据库什么都不做,并告诉您原因。

  • 最后,更新主键是一个不好的做法。
    ON CONFLICT ...插入片段并不旨在以更新主键字段。事实恰恰相反:它旨在更新单个记录中 除主键 中的字段 以外的 所有字段。

虽然我的观点是这样,但是请注意,对于主键,如果
使用“便捷”ON UPDATE NO ACTION外键使记录失败1条记录,则也不必发生冲突(这仍然比在数据库中更新10M +条记录更好)。
50张桌子ON UPDATE CASCADE…)。顺便说一句,您知道Oracle甚至没有该ON UPDATE CASCADE条款吗?您认为这是什么原因?


在这种情况下,您/不应该做什么?

  1. 不要 像我说的那样 更新主键 。您的问题对于UNIQUE约束仍然有效,但是请不要更新主键。
  2. 不要试图查看是否存在冲突的记录 。这可能需要很长时间,但仍然不可靠。
    您是否真的想选择数百万条记录,只是为了避免出现错误代码?
    另外,当您扩展到其他约束条件(CHECKEXCLUSION)时,您是否会真正键入它所需要的其他代码而没有错误,以便再次避免出现错误代码?
    最后,如果您已实现行级安全性,则冲突可能是由您看不到的记录引起的。

  3. 处理您应用中的错误代码 。接收状态为“ 良好”

  4. 如果您正在进行事务处理,请使用保存点
    这是发生DB错误的唯一令人烦恼的事情:如果在事务处理过程中遇到一个错误,那么您将开始获得current transaction is aborted, commands ignored until end of transaction block一切。
    希望您不需要回滚整个事务并从头开始重做所有操作。您可以使用下面的代码来摆脱困境。

干得好:

BEGIN;
SAVEPOINT MySavepoint;
UPDATE mytable set myuniquefield = 3; /*2+ records are going to be updated */
rollback to savepoint MySavepoint;
/*Insert Some more queries here*/
COMMIT;
2021-05-16