是否有可能(如何?)从更新后的#34;返回旧值?触发

时间:2015-02-15 09:31:35

标签: sql postgresql sql-update postgresql-9.3

UPDATE "Users" 
SET "displayName" = 'new_name' 
WHERE id = 1 
RETURNING "displayName"

上面的查询返回值。 我希望在更新后知道displayName OLD 值。我知道有可能:

 UPDATE ... 
 FROM SELECT ... 
 RETURNING ...

但我想使用AFTER UPDATE触发器。有可能"返回"来自AFTER UPDATE的旧值会以某种方式触发?如果是这样的触发器体会是什么样子?

1 个答案:

答案 0 :(得分:5)

是的,但此处涉及无触发器。只是一个简单的UPDATE

RETURNING子句根据更新后的行返回值。但是您可以在FROM子句中包含旧行,并使用 Per documentation:

  

可以计算使用表的列和/或FROM中提到的其他表的列的任何表达式。使用表格列的新(更新后)值。

解决方案:

UPDATE "Users" x
SET    "displayName" = 'new_name' 
FROM  (SELECT id, "displayName" FROM "Users" WHERE id = 1 FOR UPDATE) y 
WHERE  x.id = y.id
RETURNING y."displayName"

详细说明:

如果我的ORM不允许FROM条款怎么办?

你确定吗?如果是这样,一个简单的(更昂贵的)替代方案是运行两个语句:

BEGIN;
-- Retrieve old value first;
SELECT "displayName" FROM "Users" WHERE id = 1 FOR UPDATE;

UPDATE "Users"
SET    "displayName" = 'new_name' 
WHERE  id = 1;

COMMIT;

事务包装器(BEGIN; ... COMMIT;)和行上的锁(FOR UPDATE)用于防止可能的并发写入。如果您是唯一写入该表的人,或者偶尔过时的“旧值”可以,则可以删除这两者。除非竞争非常激烈,否则很少发生。

或者使用原始SQL绕过劣质ORM。

我可以设想解决这个问题的技巧(比如添加一个更新前的值为"displayName"的冗余列),但这样的技巧听起来像非常糟糕的主意。只需使用标准功能。