7

我有一张桌子:

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)
)

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

  1. wgs84_latitudewgs84_longitude字段都不为空
  2. utm_zoneutm_easting和中的每一个utm_northing都不为空

现在,我对如何进行更新以实现以下目标感到困惑:

  1. 当对utm_zone, utm_easting, 或进行更新时utm_northing, 然后wgs_84_latitude, wgs84_longitude,yt_albers_geom并由触发器更新
  2. wgs84_latitude或进行更新时,wgs84_longitude所有utm_字段都会更新,yt_albers_geom
  3. 当对 进行更新时yt_albers_geom,所有坐标字段都会更新。

似乎这些触发器中的任何一个都会导致触发器触发的无限循环,对吗?

4

1 回答 1

8

您可以使用标准触发器 BEFORE UPDATE OF ... ON ...来执行此操作。
手册上CREATE TRIGGER告知:

仅当列出的列中的至少一个列被提及为 UPDATE 命令的目标时,触发器才会触发。

再往下:

当它的任何列被列为 UPDATE 命令的 SET 列表中的目标时,将触发特定于列的触发器(使用 UPDATE OF column_name 语法定义的触发器)。即使未触发触发器,列的值也可能更改,因为不考虑 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_easting或进行更新时utm_northing,则 wgs_84_latitudewgs84_longitudeyt_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();

WHEN子句是可选的。防止触发器在没有实际更改值时触发。

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

当对wgs84_latitudeor进行更新时wgs84_longitude,所有 utm_字段以及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

UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> SQLfiddle 演示。

于 2012-12-02T02:56:52.270 回答