使用now()函数并执行触发器

时间:2012-12-07 15:20:20

标签: postgresql triggers timestamp infinite-loop plpgsql

我正在尝试在PostgreSQL中创建一个触发器函数,该函数应该在插入或更新记录之前检查具有相同id的记录(即id与现有记录的比较)。如果函数找到具有相同id的记录,则该条目将设置为time_dead。让我用这个例子解释一下:

INSERT INTO persons (id, time_create, time_dead, name)
VALUES (1, 'now();', ' ', 'james');

我想要一张这样的表:

 id  time_create  time-dead  name
 1   06:12                   henry   
 2   07:12                   muka

id 1time_create 06.12time_deadNULL。这与id 2相同,但下次我尝试运行具有相同ID但名称不同的insert查询时,我应该得到一个这样的表:

 id  time_create  time-dead  name
 1   06:12        14:35      henry   
 2   07:12                   muka
 1   14:35                   waks
亨利和威斯分享同一个id 1。运行insert查询后,亨利的time_dead等于waks'time_create。如果使用id 1制作了另一个条目,那么对于james来说,james的时间条目将等于waks的time_dead。等等。

到目前为止,我的功能看起来像这样。但它不起作用:

CREATE FUNCTION tr_function() RETURNS trigger AS '
BEGIN
  IF tg_op = ''UPDATE'' THEN
     UPDATE persons
     SET time_dead = NEW.time_create
     Where
         id = NEW.id
         AND time_dead IS NULL
         ;

  END IF;
  RETURN new;
END
' LANGUAGE plpgsql;

CREATE TRIGGER sofgr BEFORE INSERT OR UPDATE
        ON persons FOR each ROW
        EXECUTE PROCEDURE tr_function();

当我运行它时,它说time_dead不应该是null。有没有办法可以编写一个trigger function来自动输入inserting or updating的时间,但是当我运行select查询时,会给我上面的结果?

我做错了什么?

我的两张桌子:

CREATE TABLE temporary_object
(
  id integer NOT NULL,
  time_create timestamp without time zone NOT NULL,
  time_dead timestamp without time zone,
  PRIMARY KEY (id, time_create)
);

CREATE TABLE persons
(
  name text
)
INHERITS (temporary_object);

1 个答案:

答案 0 :(得分:1)

触发功能

CREATE FUNCTION tr_function()
  RETURNS trigger AS
$func$
BEGIN

   UPDATE persons p
   SET    time_dead = NEW.time_create
   WHERE  p.id = NEW.id
   AND    p.time_dead IS NULL
   AND    p.name <> NEW.name;

   RETURN NEW;

END
$func$ LANGUAGE plpgsql;
  • 您在触发器功能(INSERT)中错过了IF tg_op = ''UPDATE''个案。但是没有必要开始检查TG_OP,因为触发器仅在INSERT OR UPDATE上触发 - 假设您在其他触发器中不使用相同的功能。所以我删除了残骸。

  • 请注意,您不必在美元引用的字符串中转义单引号。

  • 还添加了:

    AND    p.name <> NEW.name
    

...防止INSERT立即终止(并导致无限递归)。这假设行永远不能与具有相同name的其他行一起成功。

除此之外:设置仍然不是防弹。 UPDATE可能会弄乱您的系统。我可以继续更新id或行,从而终止其他行,但不会离开继任者。请考虑禁止id上的更新。当然,这会使触发器ON UPDATE毫无意义。我怀疑你是否需要这样做。


now()as DEFAULT

如果您想now()使用time_create作为time_create的默认设置,那么就这样做。 Read the manual about setting a column DEFAULT。然后跳过INSERT中的ON INSERT,它会自动填充。

如果您想强制(阻止所有人输入其他值),请创建触发器IF TG_OP = 'INSERT' THEN NEW.time_create := now(); -- type timestamp or timestamptz! RETURN NEW; END IF; 或在触发器顶部添加以下内容:

{{1}}

假设您的错误命名列“time_create”实际上是timestamp类型 这将强制新行的当前时间戳。