首页 > 解决方案 > 在 PostgreSQL 中触发触发器时,使用“CASE WHEN”更新查询不起作用

问题描述

我尝试CASE WHEN在 PostgreSQL 中对更新查询使用条件。

我正在做的查询是:

if new.bts_trx_gc = 'Terminé' then
        update stt set stt_doe_gc_bts = (case when old.bts_trx_gc <> new.bts_trx_gc then 'Demandé' else stt_doe_gc_bts end) where stt_id = new.bts_id;
        raise info 'test est un test';
    end if;

正如我在控制台中看到的那样,触发器每次都会触发raise info。但是更新不起作用。

此查询是为了确保当用户通过 Web 界面更新字段时,更新仅在old.bts_trx_gc <> new.bts_trx_gc. 因为即使bts_trx_gc没有修改值也可能会出现在 Web 界面上,所以bts_trx_gc = Terminé会发送一个查询。而且我只想在此字段从某事变为Terminé唯一时触发更新。

考虑到上面的查询,我想做的是如果IF条件为真,old.bts_trx_gc <> new.bts_trx_gc否则bts_trx_gc = Demandé保持相同的值。

这里是如何触发功能:

create or replace function after_update_bts_trx_gc() returns trigger
    language plpgsql
as
$$
begin

    if new.bts_trx_gc = 'Terminé' then
        update stt set stt_doe_gc_bts = (case when old.bts_trx_gc <> new.bts_trx_gc then 'Demandé' else stt_doe_gc_bts end) where stt_id = new.bts_id;
        raise info 'test est un test';
    end if;

    return new;

end;
$$;

这里是触发器:

create trigger after_update_bts_trx_gc
    after update
    on etude_bts
    for each row
execute procedure after_update_bts_trx_gc();

我想从中吸取教训,所以,如果可能的话,向我解释我在这里做错了什么,或者我的方法是否缺乏洞察力。

标签: postgresqlcaseplpgsqldatabase-trigger

解决方案


我会使用 anIF有条件地运行 UPDATE,而不是 CASE 表达式。这有一个额外的好处,即您不会运行不需要的更新。

如果bts_trx_gc可以包含空值,您应该使用is distinct from而不是<>正确处理空值。

create or replace function after_update_bts_trx_gc() returns trigger
    language plpgsql
as
$$
begin
  if new.bts_trx_gc = 'Terminé' and old.bts_trx_gc IS DISTINCT FROM new.bts_trx_gc then
    UPDATE stt 
       set stt_doe_gc_bts = 'Demandé'
    WHERE stt_id = new.bts_id;

    raise info 'test est un test';
  end if;
  return new;
end;
$$;

这是我最初的答案,我忽略了 UPDATE 针对不同表的事实。不过,我将其留作参考。

不要使用 UPDATE 来更改触发器中的行。使用触发器并在满足条件时BEFORE UPDATE将值分配给行:new

create or replace function after_update_bts_trx_gc() returns trigger
    language plpgsql
as
$$
begin
  if new.bts_trx_gc = 'Terminé' and old.bts_trx_gc <> new.bts_trx_gc then
    new.stt_doe_gc_bts := 'Demandé';
    raise info 'test est un test';
  end if;
  return new;
end;
$$;

但是您需要一个 BEFORE 触发器才能使其工作:

create trigger after_update_bts_trx_gc
    BEFORE update
    on etude_bts
    for each row
execute procedure after_update_bts_trx_gc();

如果列没有改变,那么根本不触发触发器会更有效:

create trigger after_update_bts_trx_gc
    BEFORE update 
    on etude_bts
    for each row
    when (old.bts_trx_gc <> new.bts_trx_gc)
execute procedure after_update_bts_trx_gc();


推荐阅读