如果更新的版本不违反主键约束,我想更新我的postgres数据库中的行。如果可以,我想保留该行。
假设该表在col1, col2, col3
上具有主键,如果我运行这样的查询:
UPDATE table SET (col1, col2) = ('AAA', 'BBB')
WHERE col1='AAB' AND col2='BBA';
查询将失败,如果存在两个条目,我将得到重复的键错误:
'AAA', 'BBB', 'CCC'
'AAB', 'BBA', 'CCC'
即col3
在现有行和要更新的行之间是相同的。
如果我要INSERT
行,我会使用ON CONFLICT DO NOTHING
,但找不到UPDATE
的实现。是否存在等价物?
答案 0 :(得分:3)
AFAIK,没有这样的等效项。
让我们说您正在开发一个连接到postgresql数据库的应用程序,在您遇到问题时,需要牢记以下几点:
on conflict
(更新或不执行任何操作),因此有意义的是让您决定的语法。ON CONFLICT ...
无意更新主键字段。事实恰恰相反:打算在单个记录中更新所有除主键中的字段以外的字段。尽管我在这一点上,但请注意,主键无需冲突即可使查询失败
1条带有“便捷” ON UPDATE NO ACTION
外键的记录也会使其失败(这比用ON UPDATE CASCADE
更新50个表中的10M +条记录更好)。顺便说一句,您知道Oracle甚至没有ON UPDATE CASCADE
子句吗?您认为是什么原因?
在这种情况下您不能做什么?
UNIQUE
约束仍然有效,但是请请不要更新主键。CHECK
或EXCLUSION
)时,您是否会真正键入它所需要的附加代码而没有错误,以便再次避免出现错误代码?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;
答案 1 :(得分:2)
您可以将关联子查询与WHERE NOT EXISTS
子句一起使用,以确保您的更新不会产生重复项,例如:
UPDATE mytable t
SET (col1, col2) = ('AAA', 'BBB')
WHERE t.col1 = 'AAB' and t.col2 = 'BBA'
AND NOT EXISTS (
SELECT 1 FROM mytable WHERE col1 = 'AAA' AND col2 = 'BBB' AND col3 = t.col3
);
在this db fiddle中进行了测试。
编辑
正如罗曼·科诺瓦尔(Roman Konoval)所评论的那样,请注意,如果UPDATE
运行时并发事务插入相同的密钥,这仍将产生重复的密钥错误。指出更新表的主键不是一个好习惯(有关此问题的详细讨论,请参见下面来自@Lau的答案)。