Nesta entrada vou explicar como criar um disparador para actualizar automaticamente a área e perímetro das geometrias de uma tabela em PostgreSQL. Para tal, vão-se utilizar as funções ST_Area() e ST_Perimeter() de PostGIS.
Nota: Onde está esquema deve ir o nome do esquema, onde está tabela o nome da tabela e onde está geom o nome do campo com a geometria.
As seguintes linhas são para criar os campos area e perimetro e preencher os campos. Utilizar uma das opções: UTM ou Geográficas, dependendo do sistema de coordenadas do tema.
ALTER TABLE esquema.tabela ADD COLUMN area bigint;
ALTER TABLE esquema.tabela ADD COLUMN perimetro bigint;
-- Coordenadas UTM
UPDATE esquema.tabela SET area = ST_area(geom)::bigint;
UPDATE esquema.tabela SET perimetro = ST_perimeter(geom)::bigint;
-- Coordenadas Geográficas
UPDATE esquema.tabela SET area = ST_Area(Geography(geom))::bigint;
UPDATE esquema.tabela SET perimetro = ST_Length(Geography(geom))::bigint;
Decidi utilizar o tipo bigint porque considero que os valores decimais não aportam informação útil para pequenas escalas e iriam ocupar mais espaço na tabela. No entanto, para escalas maiores e se interessa a exactidão, basta com mudar bigint por float.
Agora criamos a função que preenche automáticamente os campos area e perimetro cada vez que uma geometria é inserida ou modificada. Se anteriormente alteraste bigint por float, elimina ‘::bigint’ nas linhas 5 e 6. O resultado por defeito é do tipo float e já não é necessário fazer um cast.
CREATE OR REPLACE FUNCTION esquema.fun_area_perimetro()
RETURNS trigger AS
$BODY$
BEGIN
NEW.area = ST_Area(NEW.geom)::bigint;
NEW.perimetro = ST_Perimeter(NEW.geom)::bigint;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
O exemplo dado é para temas com sistemas de coordenadas em metros, como UTM. Se o tema está em geográficas e também se pretende o resultado em metros, deve ir assim:
CREATE OR REPLACE FUNCTION esquema.fun_area_perimetro()
RETURNS trigger AS
$BODY$
BEGIN
NEW.area = ST_Area(Geography(NEW.geom))::bigint;
NEW.perimetro = ST_Length(Geography(NEW.geom))::bigint;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
Eliminamos o disparador no caso de que já exista um com o mesmo nome. Para passar a criar o disparador e indicar quando se deve executar e sobre que tabela.
DROP TRIGGER IF EXISTS trg_tabela_area_perimetro ON esquema.tabela;
CREATE TRIGGER trg_tabela_area_perimetro BEFORE INSERT OR UPDATE
ON esquema.tabela FOR EACH ROW EXECUTE PROCEDURE esquema.fun_area_perimetro();
Agora os valores de área e perímetro da tabela estarão sempre de acordo com a geometria.
39.470239
-0.376805