使默认值引用另一个 table 的 PostgreSQL 触发器

PostgreSQL trigger to make default value refer to another table

PostgreSQL 默认值不能包含变量或引用 table 或不同的 table.

中的任何其他列

但是,是否可以使用触发器来创建一个 "Default value" 将按以下方式运行。首先,让我用两个例子来说明 tables:

create table projects
(
id serial primary key,
created_at timestamp with time zone default now()
);

create table last_updated
(
project_id integer primary key references projects,
updated_at timestamp with time zone default ...
);

在第二个 table (last_updated) 中,我希望默认值类似于 default projects(created_at)。 IE。如果未为 updated_at 指定日期,请查看项目 table 中引用的 project_id,找到 created_at 日期,并将 updated_at 设置为此日期。但是,你不能按照我问题的第一段来写。

那么您如何编写提供此功能的触发器?

正确答案取决于您未指定的内容。通常,人们会对 projects table 进行更新,然后在 last_updated table 中使用 table 上的 AFTER UPDATE 触发器审核 table projects:

CREATE FUNCTION audit_project_update () RETURNS trigger AS $$
BEGIN
  INSERT INTO last_updated VALUES
    (NEW.id,   -- NEW refers to the updated record in the projects table
     now()     -- this would be the logical value, but can use NEW.created_at
     -- other columns, possibly log session_user
  );
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER tr_projects_update
  AFTER UPDATE ON projects
  FOR EACH ROW EXECUTE PROCEDURE audit_project_update();

请注意,在这种方法中,永远不会出现在 table last_updated 上创建 INSERT 而未指定 updated_at 值的情况,假设您会不是 GRANT INSERT table last_updated 上的任何角色,因为触发函数总是指定 now()。在 table 定义中,您不必再指定默认值:触发器会为您提供所需的自动化行为。

您提出的问题 - 并在下面的评论中得到确认 - 也将使用触发器,但随后在 last_updated table:

CREATE FUNCTION project_last_updated () RETURNS trigger AS $$
BEGIN
  IF (NEW.updated_at IS NULL) THEN
    SELECT created_at INTO NEW.updated_at
    FROM projects
    WHERE id = NEW.project_id;
  END IF;
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER tr_projects_update
  BEFORE INSERT ON last_updated
  FOR EACH ROW EXECUTE PROCEDURE project_last_updated();

此规范回避了一个问题,即为什么您不简单地将列 updated_at 添加到 projects table。由于 project_id 列是 last_update table 中的 PK,因此每个项目只能存储一个最后更新日期。