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

wtlkbnrh  于 2023-04-20  发布在  PostgreSQL
关注(0)|答案(1)|浏览(161)

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

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

我想要一张这样的table:

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

id 1有一个time_create 06.12,但time_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

亨利和waks共享相同的id1。在运行insert查询后,henry的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查询时,会给予我上面的结果?
我做错了什么?
两张table:

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);
z2acfund

z2acfund1#

触发函数

CREATE FUNCTION tr_function()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   UPDATE persons p
   SET    time_dead = NEW.time_create
   WHERE  p.id = NEW.id
   AND    p.name <> NEW.name
   AND    p.time_dead IS NULL;

   RETURN NEW;
END
$func$;

你在触发器函数(IF tg_op = ''UPDATE'')中遗漏了INSERT的情况。但是没有必要在开始时检查TG_OP,因为触发器只在INSERT OR UPDATE上触发-假设你在其他触发器中没有使用相同的函数。所以我删除了这个cruft。
你不需要在一个用美元引号括起来的字符串中转义单引号。
还增加了:

AND    p.name <> NEW.name

...以防止INSERT立即终止自己(并导致 * 无限递归 *)。这假设一行永远不会继承具有相同name的另一行。
旁白:设置仍然不是防弹的。UPDATE s可能会扰乱你的系统。我可以继续更新id或一行,从而终止其他行,但不留下后继行。考虑禁止在id上更新。当然,这将使触发器ON UPDATE毫无意义。我怀疑你一开始就需要它。

DEFAULT now()

如果你想使用now()作为time_create的默认值,只需这样做。Read the manual about setting a column DEFAULT。然后跳过INSERT s中的time_create,它会自动填充。
如果你想强制它(防止每个人输入不同的值),创建一个触发器ON INSERT或在触发器的顶部添加以下内容:

IF TG_OP = 'INSERT' THEN
    NEW.time_create := now();   -- type timestamp or timestamptz!
    RETURN NEW;
END IF;

这将无条件地强制新行使用当前时间戳。
(假设列“time_create”实际上是timestamp类型。

相关问题