如何在PostgreSQL 9.2.1中避免循环触发调用

时间:2012-12-01 21:29:03

标签: postgresql triggers postgis plpgsql

我有一张桌子:

CREATE TABLE field_data.soil_samples (
 pgid SERIAL NOT NULL,
 sample_id text,
 project_id text,
 utm_zone integer,
 utm_easting integer,
 utm_northing integer,
 wgs84_longitude double precision,
 wgs84_latitude double precision,
 yt_albers_geom geometry(Point,3578),
 CONSTRAINT soil_samples_pk PRIMARY KEY (pgid)
)

yt_albers_geom中的PostGIS 2.0几何体是使用触发器创建的,该触发器针对此表触发INSERTS。如果要插入的记录满足以下条件之一,则会生成几何图形:

  1. wgs84_latitudewgs84_longitude字段均不为空
  2. utm_zoneutm_eastingutm_northing均不为空
  3. 现在,我对如何进行更新以实现以下目标感到困惑:

    1. utm_zoneutm_eastingutm_northing进行更新后,wgs_84_latitudewgs84_longitudeyt_albers_geom将更新为触发器
    2. 如果对wgs84_latitudewgs84_longitude进行了更新,则会更新所有utm_字段以及yt_albers_geom
    3. yt_albers_geom进行更新后,所有坐标字段都会更新。
    4. 似乎这些触发器中的任何一个都会导致触发器触发无限循环,对吗?

1 个答案:

答案 0 :(得分:5)

您可以使用标准触发器 BEFORE UPDATE OF ... ON ...执行此操作 The manual on CREATE TRIGGER informs:

  

只有至少有一个列出的列时,触发器才会触发   提到作为UPDATE命令的目标。

进一步向下:

  

特定于列的触发器(使用UPDATE OF column_name定义的触发器   语法)将在其任何列被列为目标中时触发   UPDATE命令的SET列表。列的值可能是   即使未触发触发器也会更改,因为对其进行了更改   不考虑BEFORE UPDATE触发器的行内容。

大胆强调我的。所以没有无限循环,因为触发器内的更新不会调用另一个触发器。

测试用例

创建测试表(简化,没有不相关的行):

CREATE TABLE soil_samples (
  pgid SERIAL PRIMARY KEY

 ,utm_zone integer
 ,utm_easting integer
 ,utm_northing integer

 ,wgs84_longitude double precision
 ,wgs84_latitude double precision

 ,yt_albers_geom double precision
);

第一个要求的虚拟触发器:

  

如果对utm_zoneutm_eastingutm_northing进行了更新,那么   <{1}},wgs_84_latitudewgs84_longitude由触发器更新。

yt_albers_geom

CREATE OR REPLACE FUNCTION trg_upbef_utm() RETURNS trigger AS $func$ BEGIN NEW.wgs84_latitude := NEW.wgs84_latitude + 10; NEW.wgs84_longitude := NEW.wgs84_longitude + 10; NEW.yt_albers_geom := NEW.yt_albers_geom + 10; RETURN NEW; END $func$ LANGUAGE plpgsql; CREATE TRIGGER upbef_utm BEFORE UPDATE OF utm_zone, utm_easting, utm_northing ON soil_samples FOR EACH ROW WHEN (NEW.utm_zone IS DISTINCT FROM OLD.utm_zone OR NEW.utm_easting IS DISTINCT FROM OLD.utm_easting OR NEW.utm_northing IS DISTINCT FROM OLD.utm_northing) -- optional EXECUTE PROCEDURE trg_upbef_utm(); 子句是可选的。当没有值实际发生变化时,阻止触发器触发。

第二个要求的虚拟触发器:

  

WHENwgs84_latitude进行更新后,全部更新   更新了u wgs84_longitude字段,以及tm_

yt_albers_geom

沿着这些方向触发第三项要求......

测试

CREATE OR REPLACE FUNCTION trg_upbef_wgs84()  RETURNS trigger AS
$func$
BEGIN
   NEW.utm_zone       := NEW.utm_zone + 100;
   NEW.utm_easting    := NEW.utm_easting + 100;
   NEW.utm_northing   := NEW.utm_northing + 100;
   NEW.yt_albers_geom := NEW.yt_albers_geom + 100;

   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER upbef_wgs84
 BEFORE UPDATE OF wgs84_latitude, wgs84_longitude ON soil_samples
 FOR EACH ROW
 WHEN (NEW.wgs84_latitude  IS DISTINCT FROM OLD.wgs84_latitude OR
       NEW.wgs84_longitude IS DISTINCT FROM OLD.wgs84_longitude)  -- optional
 EXECUTE PROCEDURE trg_upbef_wgs84();

触发器INSERT INTO soil_samples VALUES (1, 1,1,1, 2,2, 3) RETURNING *; :空更新,没有任何反应:

upbef_utm

使用实际更改进行更新:UPDATE soil_samples SET utm_zone = 1 RETURNING *; 不会触发第二个触发器upbef_wgs84

UPDATE OF utm_zone

触发UPDATE soil_samples SET utm_zone = 0 RETURNING *;

upbef_wgs84

-> SQLfiddle demo.