我正在更新 Postgres 8.4 数据库(来自 C# 代码),基本任务非常简单:更新现有行或插入新行(如果尚不存在)。通常我会这样做:
UPDATE my_table
SET value1 = :newvalue1, ..., updated_time = now(), updated_username = 'evgeny'
WHERE criteria1 = :criteria1 AND criteria2 = :criteria2
如果 0 行受到影响,则执行插入:
INSERT INTO my_table(criteria1, criteria2, value1, ...)
VALUES (:criteria1, :criteria2, :newvalue1, ...)
不过,有一个轻微的扭曲。我不想更改 updated_time 和 updated_username 列,除非任何新值实际上与现有值不同以避免误导用户关于数据更新的时间。
如果我只执行更新,那么我也可以为值添加 WHERE 条件,但这在这里不起作用,因为如果数据库已经是最新的,更新将影响 0 行,然后我会尝试插入。
除了 SELECT,然后 UPDATE 或 INSERT 之外,谁能想到一种优雅的方式来做到这一点?
最佳答案
查看 BEFORE UPDATE 触发器以检查并设置正确的值:
CREATE OR REPLACE FUNCTION my_trigger() RETURNS TRIGGER LANGUAGE plpgsql AS
$$
BEGIN
IF OLD.content = NEW.content THEN
NEW.updated_time= OLD.updated_time; -- use the old value, not a new one.
ELSE
NEW.updated_time= NOW();
END IF;
RETURN NEW;
END;
$$;
现在您甚至不必在 UPDATE 查询中提及字段 updated_time,它将由触发器处理。
http://www.postgresql.org/docs/current/interactive/plpgsql-trigger.html
关于sql - Postgres UPSERT(INSERT 或 UPDATE)仅当值不同时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3464750/