- PostGIS Cookbook
- Paolo Corti Thomas J. Kraft Stephen Vincent Mather Bborie Park
- 815字
- 2021-07-19 18:29:43
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);
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
- Practical Data Analysis Cookbook
- Spring Cloud Alibaba核心技術與實戰案例
- Arduino by Example
- 區塊鏈架構與實現:Cosmos詳解
- 精通Linux(第2版)
- Hands-On Functional Programming with TypeScript
- C++面向對象程序設計習題解答與上機指導(第三版)
- Learning Unity 2D Game Development by Example
- Learning JavaScript Data Structures and Algorithms
- PHP從入門到精通(第4版)(軟件開發視頻大講堂)
- 執劍而舞:用代碼創作藝術
- Illustrator CC平面設計實戰從入門到精通(視頻自學全彩版)
- Django實戰:Python Web典型模塊與項目開發
- BeagleBone Robotic Projects(Second Edition)
- 30天學通C#項目案例開發