【问题标题】:in postgres, splitting an update between two tables using Rules在 postgres 中,使用规则在两个表之间拆分更新
【发布时间】:2012-02-01 06:26:49
【问题描述】:

尝试使用规则维护编辑日志。

create table t1(
    id serial primary key,
    c1 text,
    ... );

create table edit_log(
    id int references t1,
    editor_id int references users,
    edit_ts timestamp default current_timestamp );

有更新,希望update t1insert into edit_lot

update t1 set c1='abc', ... where id=456;
insert into edit_log( id, editor_id, current_timestamp );

对于任意数量的列,这将是一个非常简单的 except,例如,

update t1 set c1='abc', c2='def', editor_id=123 where id=456;
update t1 set c3='xyz', editor_id=123 where id=456;

如何为此编写规则?

【问题讨论】:

  • 可以用 ALSO 规则完成,试试吧。不要忘记日志表的 PK 将是 {id,edit_ts}。插入应该总是检查日志表中的“NOT EXISTS”。删除有点特殊。并且总是检查生成的查询计划。
  • right - ALSO Rule 规则(原样)。但是如何处理任意数量的列?
  • 由于您只记录事件(而不是数据),因此任意列都无关紧要。一条记录被更新(插入、删除)命中,或者不是。也许我不明白你的意思?

标签: sql postgresql rules


【解决方案1】:

我认为trigger 会比规则更好地为您服务。考虑这个演示。

测试设置

CREATE TEMP TABLE t1(id int, editor_id int, c1 text);
INSERT INTO t1(id, editor_id) VALUES (1,1),(2,2);
CREATE TEMP TABLE edit_log(id int, editor_id int, edit_ts timestamp);

创建触发函数

CREATE OR REPLACE FUNCTION trg_t1_upaft_log()
  RETURNS trigger AS
$BODY$
BEGIN

IF OLD IS DISTINCT FROM NEW THEN -- to avoid empty updates
    INSERT INTO edit_log(id, editor_id, edit_ts)
    VALUES(NEW.id, NEW.editor_id, now()::timestamp);
END IF;

RETURN NULL; -- trigger will be fired AFTER updates, return value is irrelevant.

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

创建触发器

CREATE TRIGGER upaft_log
  AFTER UPDATE ON t1
  FOR EACH ROW
  EXECUTE PROCEDURE trg_t1_upaft_log();

测试

UPDATE t1 SET c1 = 'baz' WHERE id = 1;
SELECT * FROM edit_log; -- 1 new entry

UPDATE t1 SET c1 = 'baz' WHERE id = 1;
SELECT * FROM edit_log;  -- no new entry, update changed nothing!

UPDATE t1 SET c1 = 'blarg';
SELECT * FROM edit_log;  -- 2 new entries, update changed two rows.

清理

DROP TRIGGER upaft_log ON t1;
DROP FUNCTION trg_t1_upaft_log()
-- Temp. tables will be dropped automatically at end of session.

评论

很难或根本不可能(取决于您的设置细节)确定哪些行已更新。

trigger AFTER UPDATE 可以事后决定,是更好的选择。在这种情况下也很容易与(大多数)其他触发器和/或规则集成。

【讨论】:

  • 当前正在使用您所概述的触发器。但试图通过将editor_id 作为更新表的一部分来避免作弊。
  • @ccyoung:如果editor_id 可以从current_usersession_user 派生,则您不需要更新表中的额外列。触发器不是作弊。这是本案的典型解决方案。
  • 与大多数 Web 应用程序一样,所有普通用户共享 db 用户名。由于 pg 连接非常昂贵,因此这是有道理的。 pg 不知道应用程序用户。作弊必须维护更新表中的editor_id 列,而不是使用触发器。使用规则而不是触发器背后的想法是试图绕过这个作弊。
猜你喜欢
  • 2014-01-11
  • 2019-04-11
  • 2018-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多