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值.我想知道更新后的OLD值displayName.我知道有可能:
UPDATE ...
FROM SELECT ...
RETURNING ...
Run Code Online (Sandbox Code Playgroud)
但我想使用AFTER UPDATE触发器.是否有可能以AFTER UPDATE某种方式从触发器"返回"旧值?如果是这样的触发器体如何?
是的,但这里根本没有涉及触发器.只是一个平原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)
详细说明:
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"),但这样的技巧听起来是一个非常糟糕的主意.只需使用标准功能.