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

问题描述 投票:0回答:1

我正在尝试在 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 1
有一个
time_create 06.12
time_dead
NULL
。这与
id 2
相同,但下次我尝试使用相同的 id 但不同的名称运行
insert
查询时,我应该得到一个这样的表:

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

henry 和 waks 共享相同的

id
1
。在运行
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
查询时,会给我像上表一样的结果?

我做错了什么?

我的两张桌子:

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);
postgresql triggers timestamp infinite-loop plpgsql
1个回答
2
投票

触发功能

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

您在触发功能 (

INSERT
) 中遗漏了
IF tg_op = ''UPDATE''
案例。但是不需要首先检查
TG_OP
,因为触发器只在
INSERT OR UPDATE
上触发 - 假设您没有在其他触发器中使用相同的功能。所以我删除了 cruft.

您不必在美元引号字符串中转义单引号。

还添加了:

AND    p.name <> NEW.name

... 以防止

INSERT
的立即终止(并导致 无限递归)。这假设一行永远不会在具有相同
name
的另一行之后。

旁白:设置仍然不是防弹的。

UPDATE
s 可能会扰乱您的系统。我可以继续更新
id
或一行,从而终止其他行但不留下后继行。考虑禁止对
id
的更新。当然,这会使触发器
ON UPDATE
毫无意义。我怀疑你需要这个开始。

 DEFAULT now()

如果你想使用

now()
作为
time_create
的默认设置,就这样做吧。 阅读有关设置列的手册
DEFAULT
。然后在
time_create
s中跳过
INSERT
就自动填充了

如果你想 force 它(防止每个人输入不同的值)创建一个触发器

ON INSERT
或在触发器顶部添加以下内容:

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

无条件地强制新行的当前时间戳。
(假设您的列“time_create”实际上是类型

timestamp
。)

© www.soinside.com 2019 - 2024. All rights reserved.