官术网_书友最值得收藏!

Using triggers to populate a geometry column

In this recipe, we imagine that we have ongoing updates to our database, which needs spatial representation; however, in this case, we want a hard-coded geometry column to be updated each time an INSERT operation takes place on the database, converting our x and y values to geometry as they are inserted in the database.

The advantage of this approach is that the geometry is then registered in the geometry_columns view, and therefore this approach works reliably with more PostGIS client types than creating a geospatial view. This also provides the advantage of allowing for a spatial index that can significantly speed up a variety of queries. The disadvantage for users using PostgreSQL versions lower than Version 9.0 is that, without a WHERE clause within the trigger, every time an insert takes place, the trigger will be calculated on all points to create geometry. This method could be very expensive on large datasets. However, for users of PostgreSQL 9.0 and later, a WHERE clause makes this trigger perform quickly, as we can constrain the trigger to only those rows that have no geometry yet populated.

Getting ready

We will start by creating another table of random points with x, y, and z values, as shown in the following query:

DROP TABLE IF EXISTS chp02.xwhyzed1 CASCADE;
CREATE TABLE chp02.xwhyzed1
(
 x numeric,
 y numeric,
 z numeric
)
WITH (OIDS=FALSE);
ALTER TABLE chp02.xwhyzed1 OWNER TO postgres;
ALTER TABLE chp02.xwhyzed1 ADD COLUMN gid serial;
ALTER TABLE chp02.xwhyzed1 ADD PRIMARY KEY (gid);

INSERT INTO chp02.xwhyzed1 (x, y, z)
 VALUES (random()*5, random()*7, random()*106);
INSERT INTO chp02.xwhyzed1 (x, y, z)
 VALUES (random()*5, random()*7, random()*106);
INSERT INTO chp02.xwhyzed1 (x, y, z)
 VALUES (random()*5, random()*7, random()*106);
INSERT INTO chp02.xwhyzed1 (x, y, z)
 VALUES (random()*5, random()*7, random()*106);

How to do it...

Now we need a geometry column to populate. By default, the geometry column will be populated with null values. We populate a geometry column using the following query:

SELECT AddGeometryColumn ('chp02','xwhyzed1','geom',3734,'POINT',2);

We now have a column called the_geom with an SRID of 3734, that is, a point geometry type in two dimensions. Since we have x, y, z data, we could, in principle, populate a 3D point table using a similar approach.

Since all the geometry values are currently null, we will populate them using an UPDATE statement as follows:

UPDATE chp02.xwhyzed1
 SET geom = ST_SetSRID(ST_MakePoint(x,y), 3734);

The query here is simple when broken down. We update the table xwhyzed1 and set the the_geom column using ST_MakePoint, construct our point using the x and y columns, and wrap it in an ST_SetSRID function in order to apply the appropriate spatial reference information. So far we have just set the table up. Now we need to create a trigger in order to continue to populate this information once the table is in use. The first part of the trigger is a newly populated geometry function using the following query:

CREATE OR REPLACE FUNCTION chp02.xyz_pop_geom()
 RETURNS TRIGGER AS $popgeom$

BEGIN
 IF(TG_OP='INSERT') THEN

 UPDATE chp02.xwhyzed1
 SET geom = ST_SetSRID(ST_MakePoint(x,y), 3734)
 WHERE geom IS NULL
 ;

 END IF;
 RETURN NEW;
END;

$popgeom$ LANGUAGE plpgsql;

In essence, we have created a function that does exactly what we did manually: it updates the table's geometry column with the combination of ST_SetSRID and ST_MakePoint. The one exception here is that we've added a WHERE clause that allows us to apply this only to rows that have no geometry populated. This is the performant choice.

There's more...

While we have a function created, we have not yet applied it as a trigger to the table. Let us do that here as follows:

CREATE TRIGGER popgeom_insert
 AFTER INSERT ON chp02.xwhyzed1
 FOR EACH STATEMENT EXECUTE PROCEDURE chp02.xyz_pop_geom();

Now, any inserts into our table should be populated with new geometry records. Let us do a test insert using the following query:

INSERT INTO chp02.xwhyzed1 (x, y, z)
 VALUES (random()*5, random()*7, random()*106); 

Extending further...

So far we've implemented an insert trigger. What if the value changes for a particular row? In that case, we will require a separate update trigger. We'll change our original function to test the UPDATE case, and we'll use WHEN in our trigger to constrain updates to the column being changed.

Also note that the following function is written with the assumption that the user wants to always update the changing geometries based on the changing values:

CREATE OR REPLACE FUNCTION chp02.xyz_pop_geom()
 RETURNS TRIGGER AS $popgeom$

BEGIN
 IF(TG_OP='INSERT') THEN

 UPDATE chp02.xwhyzed1
 SET geom = ST_SetSRID(ST_MakePoint(x,y), 3734)
 WHERE geom IS NULL
 ;

 ELSIF(TG_OP='UPDATE') THEN
 UPDATE chp02.xwhyzed1
 SET geom = ST_SetSRID(ST_MakePoint(x,y), 3734)
 ; 

 END IF;
 RETURN NEW;
END;
$popgeom$ LANGUAGE plpgsql;

CREATE TRIGGER popgeom_insert
 AFTER INSERT ON chp02.xwhyzed1
 FOR EACH ROW
 EXECUTE PROCEDURE chp02.xyz_pop_geom();

CREATE TRIGGER popgeom_update
 AFTER UPDATE ON chp02.xwhyzed1
 FOR EACH ROW
 WHEN (OLD.X IS DISTINCT FROM NEW.X AND OLD.Y IS DISTINCT FROM NEW.Y)
 EXECUTE PROCEDURE chp02.xyz_pop_geom();

See also

  • The Using geospatial views recipe
主站蜘蛛池模板: 嘉义县| 和平县| 任丘市| 本溪市| 修水县| 阜阳市| 平顶山市| 琼海市| 峨眉山市| 平乐县| 京山县| 卢湾区| 南和县| 青海省| 清镇市| 嵊泗县| 库尔勒市| 米脂县| 财经| 道孚县| 云霄县| 都安| 唐河县| 乌兰县| 卢湾区| 沂南县| 积石山| 顺昌县| 福清市| 红原县| 花莲市| 柘荣县| 桐柏县| 万荣县| 齐齐哈尔市| 英德市| 汉阴县| 博客| 黄大仙区| 绥芬河市| 荣成市|