我正在更新一个PASGRES8.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, ...)

不过,有一个小小的转折。我不想改变更新的时间和更新的UsUnError列,除非任何新的值实际上与现有的值不同,以避免在数据更新时误导用户。
如果我只是在做一个更新,那么我也可以添加值的WHERE条件,但这在这里不起作用,因为如果DB已经是最新的,那么更新将影响0行,然后我将尝试插入。
除了SELECT之外,还有谁能想出一个优雅的方法来完成这个任务,然后要么更新要么插入?

最佳答案

查看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;
$$;

现在您甚至不必在更新查询中提到字段updated_time,它将由触发器处理。
http://www.postgresql.org/docs/current/interactive/plpgsql-trigger.html

09-04 05:09