Postgresql忽略触发器上的“何时”条件

Posted

技术标签:

【中文标题】Postgresql忽略触发器上的“何时”条件【英文标题】:Postgresql ignoring 'when' condition on trigger 【发布时间】:2019-05-01 09:50:35 【问题描述】:

触发器似乎忽略了我定义中的“何时条件”,但我不确定为什么。我正在运行以下命令:

create trigger trigger_update_candidate_location
after update on candidates
for each row
when (
  OLD.address1 is distinct from NEW.address1
  or
  OLD.address2 is distinct from NEW.address2
  or
  OLD.city is distinct from NEW.city
  or
  OLD.state is distinct from NEW.state
  or
  OLD.zip is distinct from NEW.zip
  or
  OLD.country is distinct from NEW.country

)
execute procedure entities.tf_update_candidate_location();

但是当我再次查看它时,我得到以下信息:

-- auto-generated definition
create trigger trigger_update_candidate_location
  after update
  on candidates
  for each row
execute procedure tf_update_candidate_location();

这是有问题的,因为我调用的过程最终会在同一张表上针对不同的列(lat/lng)进行更新。由于忽略了“何时”条件,这会产生一个无限循环。

我的目的是观察地址变化,在另一个表上查找以获取 lat/lng 值。

Postgresql 版本:10.6 IDE:DataGrip 2018.1.3

【问题讨论】:

不是 Postgres 忽略了你的意图,而是 DataGrip 的错误。 @klin 很有趣,这并不让我感到惊讶 - 你从哪里学到的? Postgres 是我多年的朋友,我知道它不能做这么愚蠢的事情。 【参考方案1】:

您究竟是如何创建和“检查”的?使用数据夹?

WHEN 条件是在 Postgres 9.0 中添加的。一些老的(或糟糕的)客户可能已经过时了。可以肯定的是,使用以下命令签入 pgsql:

SELECT pg_get_triggerdef(oid, true)
FROM   pg_trigger
WHERE  tgrelid = 'candidates'::regclass  -- schema-qualify name to be sure
AND    NOT tgisinternal;

任何实际的WHEN 限定都以内部格式存储在pg_trigger.tgqual 中,顺便说一句。详情见手册here。

还有你当前的search_path 是什么以及表candidates 的架构是什么?

candidates 是非限定的,而触发函数entities.tf_update_candidate_location() 具有模式限定......你不会混淆不同数据库模式中的同名表,是吗?

除此之外,您还可以使用这种更短的等效语法进行简化:

create trigger trigger_update_candidate_location
after update on candidates   -- schema-qualify??
for each row
when (
   (OLD.address1, OLD.address2, OLD.city, OLD.state, OLD.zip, OLD.country)
   IS DISTINCT FROM
   (NEW.address1, NEW.address2, NEW.city, NEW.state, NEW.zip, NEW.country)
   )
execute procedure entities.tf_update_candidate_location();

【讨论】:

是的,使用 DataGrip 中的控制台,我现在将 IDE 更新到最新版本。当前搜索路径是 entities 所以它实际上是 entities.candidate 当我在你的帖子中运行选择时我没有得到任何回复。 然后在没有AND tgqual IS NOT NULL 的情况下再次测试以获得没有WHEN 资格的触发器。我添加了一个更好的测试来获取所有有或没有WHEN 资格的用户触发器。 更新 DataGrip 并没有改变任何东西,但是我已经用你的语法(加上entities.candidates 架构)重新构建了触发器,现在当我运行选择时,我得到了以下看起来更正确的内容 CREATE TRIGGER trigger_update_candidate_location AFTER UPDATE ON entities.candidates FOR EACH ROW WHEN (old.address1::text IS DISTINCT FROM new.address1::text OR old.address2::text IS DISTINCT FROM new.address2::text OR old.city::text IS DISTINCT FROM new.city::text OR old.state::text IS DISTINCT FROM new.state::text OR old.zip::text IS DISTINCT FROM new.zip::text OR old.country::text IS DISTINCT FROM new.country::text) EXECUTE PROCEDURE entities.tf_update_candidate_location 这似乎现在按预期工作,没有无限循环。这对我来说意味着问题是我在原始帖子中的格式。【参考方案2】:

很遗憾,这是 DataGrip 的问题。请按照票证在修复时收到通知。 https://youtrack.jetbrains.com/issue/DBE-7247

【讨论】:

以上是关于Postgresql忽略触发器上的“何时”条件的主要内容,如果未能解决你的问题,请参考以下文章

从 PostgreSQL 中的字段中提取数字

为啥/何时我必须点击两次才能触发 iOS 上的点击

在 PostgreSQL 中按多个内连接的条件计数

PostgreSQL新手入门

postgresql 上的更新类型

postgresql是啥数据库