在 PostgreSQL 中触发触发器时使用“CASE WHEN”更新查询不起作用
update query using `CASE WHEN` not working when trigger fired in PostgreSQL
我尝试对 PostgreSQL 中的更新查询使用 CASE WHEN
条件。
我正在做的查询是:
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();
我想从中吸取教训,所以,如果可能的话,请向我解释我在这里做错了什么,或者我的方法是否缺乏洞察力。
我会使用 IF
有条件地 运行 UPDATE,而不是 CASE 表达式。这还有一个额外的好处,即您不会 运行 不需要的更新。
如果 bts_trx_gc
可以包含空值,您应该使用 is distinct from
而不是 <>
来正确处理 NULL 值。
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;
$$;
这是我最初的回答,我忽略了更新针对不同 table 的事实。不过,我将其留作参考。
不要使用更新来更改触发器中的行。使用 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();
CASE WHEN 在触发器中对我不起作用(总是 returns 在第一个 WHEN 上为真):
myTag = '[' || TG_TABLE_NAME ||
CASE WHEN TG_TABLE_NAME = 'scac_proformat'
THEN
CASE WHEN tg_op IN ('UPDATE','INSERT')
THEN coalesce(NEW.format_type,'P')
ELSE coalesce(OLD.format_type,'P')
END
ELSE ''
END
|| ']';
这样就可以了:
IF TG_TABLE_NAME = 'scac_proformat'
THEN
myTag = '[' || TG_TABLE_NAME ||
CASE WHEN tg_op IN ('UPDATE','INSERT')
THEN coalesce(NEW.format_type,'P')
ELSE coalesce(OLD.format_type,'P')
END
|| ']';
END IF;
IF TG_TABLE_NAME != 'scac_proformat'
THEN
myTag = '[' || TG_TABLE_NAME || ']';
END IF;
我不确定内部 CASE ;)
我尝试对 PostgreSQL 中的更新查询使用 CASE WHEN
条件。
我正在做的查询是:
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();
我想从中吸取教训,所以,如果可能的话,请向我解释我在这里做错了什么,或者我的方法是否缺乏洞察力。
我会使用 IF
有条件地 运行 UPDATE,而不是 CASE 表达式。这还有一个额外的好处,即您不会 运行 不需要的更新。
如果 bts_trx_gc
可以包含空值,您应该使用 is distinct from
而不是 <>
来正确处理 NULL 值。
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;
$$;
这是我最初的回答,我忽略了更新针对不同 table 的事实。不过,我将其留作参考。
不要使用更新来更改触发器中的行。使用 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();
CASE WHEN 在触发器中对我不起作用(总是 returns 在第一个 WHEN 上为真):
myTag = '[' || TG_TABLE_NAME ||
CASE WHEN TG_TABLE_NAME = 'scac_proformat'
THEN
CASE WHEN tg_op IN ('UPDATE','INSERT')
THEN coalesce(NEW.format_type,'P')
ELSE coalesce(OLD.format_type,'P')
END
ELSE ''
END
|| ']';
这样就可以了:
IF TG_TABLE_NAME = 'scac_proformat'
THEN
myTag = '[' || TG_TABLE_NAME ||
CASE WHEN tg_op IN ('UPDATE','INSERT')
THEN coalesce(NEW.format_type,'P')
ELSE coalesce(OLD.format_type,'P')
END
|| ']';
END IF;
IF TG_TABLE_NAME != 'scac_proformat'
THEN
myTag = '[' || TG_TABLE_NAME || ']';
END IF;
我不确定内部 CASE ;)