是否有可能(如何?)从"更新后"触发器返回旧值

use*_*521 3 sql postgresql sql-update postgresql-9.3

UPDATE "Users" 
SET "displayName" = 'new_name' 
WHERE id = 1 
RETURNING "displayName"
Run Code Online (Sandbox Code Playgroud)

上面的查询返回NEW值.我想知道更新后的OLDdisplayName.我知道有可能:

 UPDATE ... 
 FROM SELECT ... 
 RETURNING ...
Run Code Online (Sandbox Code Playgroud)

但我想使用AFTER UPDATE触发器.是否有可能以AFTER UPDATE某种方式从触发器"返回"旧值?如果是这样的触发器体如何?

Erw*_*ter 6

是的,但这里根本没有涉及触发器.只是一个平原UPDATE.

RETURNING子句根据更新的行返回值.但是您可以在FROM子句中包含旧行并使用.每个文件:

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"
Run Code Online (Sandbox Code Playgroud)

详细说明:

如果我的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;
Run Code Online (Sandbox Code Playgroud)

事务包装器(BEGIN; ... COMMIT;)和行(FOR UPDATE)上的锁是为了防止可能的并发写入.如果您是唯一写入该表的人,或者偶尔过时的"旧值"可以,则可以删除这两者.除了非常有竞争力的设置外,很少发生.

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

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