我正在更新Postgres 8.4数据库(从C#代码),基本任务很简单:UPDATE一个现有行,或者如果还不存在,请插入一个新的行.通常我会这样做:
UPDATE my_table SET value1 = :newvalue1,...,updated_time = now(),updated_username = 'evgeny' WHERE criteria1 = :criteria1 AND criteria2 = :criteria2
如果0行受到影响,则执行一个INSERT:
INSERT INTO my_table(criteria1,criteria2,value1,...) VALUES (:criteria1,:criteria2,:newvalue1,...)
虽然有一点点扭曲.我不想更改updated_time和updated_username列,除非任何新值与现有值实际不同,以避免误导用户何时更新数据.
如果我只是做一个UPDATE,那么我可以为这个值添加WHERE条件,但是这不会在这里工作,因为如果数据库已经是最新的,UPDATE会影响0行,然后我会尝试INSERT.
任何人都可以想到一个优雅的方式来做这个,除了SELECT,那么UPDATE还是INSERT?
解决方法
两件事情在这里
首先,根据数据库中的活动级别,您可能会在检查记录和插入其中的过程中创建该记录的过程中遇到竞争条件.
本手册包含如何执行此操作的示例
link example
首先,根据数据库中的活动级别,您可能会在检查记录和插入其中的过程中创建该记录的过程中遇到竞争条件.
本手册包含如何执行此操作的示例
link example
为了避免进行更新,有suppress_redundant_updates_trigger()过程.要按照您的愿望使用,您必须在更新触发之前必须有两个,如果没有更改,那么第一个将调用suppress_redundant_updates_trigger()来中止更新,第二个将在进行更新时设置时间戳和用户名.触发器按字母顺序触发.
这样做也意味着更改上面的示例中的代码,以便在更新之前首先尝试插入.
抑制更新如何工作的示例:
DROP TABLE sru_test; CREATE TABLE sru_test(id integer not null primary key,data text,updated timestamp(3)); CREATE TRIGGER z_min_update BEFORE UPDATE ON sru_test FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); DROP FUNCTION set_updated(); CREATE FUNCTION set_updated() RETURNS TRIGGER AS $$ DECLARE BEGIN NEW.updated := now(); RETURN NEW; END; $$LANGUAGE plpgsql; CREATE TRIGGER zz_set_updated BEFORE INSERT OR UPDATE ON sru_test FOR EACH ROW EXECUTE PROCEDURE set_updated(); insert into sru_test(id,data) VALUES (1,'Data 1'); insert into sru_test(id,data) VALUES (2,'Data 2'); select * from sru_test; update sru_test set data = 'NEW'; select * from sru_test; update sru_test set data = 'NEW'; select * from sru_test; update sru_test set data = 'ALTERED' where id = 1; select * from sru_test; update sru_test set data = 'NEW' where id = 2; select * from sru_test;