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

时间:2015-02-20 20:04:46

标签: postgresql triggers count timestamp

我有一个简单的表,主键,时间戳和&计数。

我有触发器来自动更新时间戳&在更新事件之前计数是标准的。

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

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

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

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

谢谢!

/* 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();

2 个答案:

答案 0 :(得分:0)

最后一个问题:

  

未来的数据库更新是否会拒绝该事务,因为没有任何变化?

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

  

有没有办法在不使用更新的情况下启动表行上的所有关联触发器?或者这是一个好的解决方案吗?

这是一个合理的解决方案,但我称之为代码味道。通常,触发器不是关系型的。纯粹的关系数据库更容易推理。在纯粹的关系数据库中,你不会做这样的事情。所以你应该问问自己,触发器是否是一个好主意。当然,答案可能是“是的,因为没有其他合理的方法可以做到这一点。”但你应该考虑它,而不是假设情况就是这样。

答案 1 :(得分:0)

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

create or replace function add_update_user(varchar) returns void as $$
  begin
    if exists (select 1 from users where username = $1) then
      update users set timestamp = current_timestamp where username = $1;
      update users set count = count + 1 where username = $1;
    else
      insert into users (username) values ($1);
    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');