如何在没有看似多余的更新语句的情况下启动触发器?

How to kick off triggers without a seemly redundant update statement?

我有一个带有主键、时间戳和计数的简单 table。

我有触发器自动更新时间戳并在更新事件之前按标准计数。

要执行触发器,我必须执行一个事件(例如更新)。尽管它可以执行标准更新,但我并不完全满意table,因为它似乎是多余的。

update users set username = 'johndoe' where username = 'johndoe';

从 SQL 的角度来看,明确更新字段会感觉更好,但我宁愿将自动更新留给触发器,以便代码库与模式实现很好地分离(以便以后升级)。

有没有办法在不使用更新的情况下启动 table 行上的所有关联触发器?或者这是一个好的解决方案?由于没有任何变化,未来的数据库更新是否会拒绝该交易?

谢谢!

/* update_timestamp function to call from trigger */
create function update_timestamp() returns trigger as $$
begin
  NEW.timestamp := current_timestamp;
  return NEW;
end;
$$ language plpgsql;

/* update_count function to call from trigger */
create function update_count() returns trigger as $$
begin
  NEW.count := OLD.count + 1;
  return NEW;
end;
$$ language plpgsql;

/* users table */
create table users(
username character varying(50) not null,
timestamp timestamp not null default current_timestamp,
count bigint not null default 1);

/* timestamp & count triggers */
create trigger users_timestamp_upd before update on users for each row execute procedure update_timestamp();
create trigger users_count_upd before update on users for each row execute procedure update_count();

最后一个问题在先:

Will a future database update refuse the transaction since nothing is changing?

没有。这是完全有效的 SQL 语法。拒绝它会在 SQL 标准支持方面倒退,这对于任何生产就绪的 RDBMS 来说都是非常不规则的。此外,该标准要求 BEFORE UPDATE 在所有受影响的行上触发 运行,即使这些行实际上并未更改。

Is there a way to kick-off all associated triggers on a table row without using update? Or is this an ok solution?

就目前而言,这是一个合理的解决方案,但我将其称为代码异味。一般来说,触发器不是相关的。纯关系数据库更容易推理。在纯关系数据库中,您不会做这样的事情。所以你应该问问自己,触发器是否是一个好主意。当然,答案很可能是"yes, because there's no other reasonable way of doing this."但你应该实际考虑一下,而不是假设是这样。

谢谢。决定使用函数而不是触发器。直接从 PHP.

调用它
create or replace function add_update_user(varchar) returns void as $$
  begin
    if exists (select 1 from users where username = ) then
      update users set timestamp = current_timestamp where username = ;
      update users set count = count + 1 where username = ;
    else
      insert into users (username) values ();
    end if;
  end;
$$ language plpgsql;

create table users(
  username character varying(50) not null,
  timestamp timestamp not null default current_timestamp,
  count bigint not null default 1);

select add_update_user('testusername');