在 Postgres 事务中,如果存在则删除的最佳方法是什么,否则失败?

In a Postgres transaction, what is the best way to delete if exists, and fail otherwise?

在 Postgres 中,我想在事务中执行大量删除和写入操作,但如果要删除的行不存在,我想使事务失败。执行此操作的最佳方法是什么?

使用 PL/pgSQL 代码块(在 FUNCTIONPROCEDUREDO 语句中)并在 DELETE 未找到时引发异常任何行。您可以使用特殊变量 FOUND:

DO
$do$
BEGIN
   DELETE FROM tbl1 WHERE id = 1;
   
   IF NOT FOUND THEN
      RAISE EXCEPTION 'Failed to delete!';
   END IF;
   
   INSERT INTO tbl2 (col1) VALUES ('foo');
END
$do$;

引发异常会回滚整个事务。

The manual:

Note in particular that EXECUTE changes the output of GET DIAGNOSTICS, but does not change FOUND.

参见:

  • Dynamic SQL (EXECUTE) as condition for IF statement

如果没有行被删除,这个想法会引发异常:

delete from mytable
where id = 123
and 1/(select count(*) from mytable where id = 123) > 0

这适用于子查询,它应该具有与删除的 where 子句相同的 where 子句,如果没有要删除的匹配行,则返回 0,这会导致被零除错误将自动使事务失败,导致所有工作回滚。