创建 Postgres/PostGIS 函数以根据空间查询更新 table 值

Creating Postgres/PostGIS function to update table values based on spatial query

我对 Postgres 和 PostGIS 运行查询和脚本有一定的经验,但没有创建函数的经验。我觉得我想要实现的目标比我看到的例子要复杂得多,所以我希望有人能帮助我。

我正在创建一个 Web 应用程序,它允许用户根据与在地图上绘制的多边形的交集以及在表单中输入的一些值来更新存储在空间 table 中的地段边界记录。我不知道是否有一种方法可以将数据库记录的子集存储在一个数组中并对其进行迭代,依次更新每条记录,或者我是否必须 运行 在函数中单独更新脚本。我也不确定是否可以将 table 名称作为参数传递给函数,因为我只想 运行 函数并让它在不同的 tables.

如果我要创建一个函数,通过简单地 运行 一堆单独的更新脚本来完成我想让它做的所有事情,它可能看起来像下面这样(函数没有实际测试):

CREATE OR REPLACE FUNCTION updateLots(wkt_geom text, tablename varchar(25), landuse varchar(25), density NUMERIC(4,1))
  RETURNs VOID AS
$$
  BEGIN
    UPDATE [tablename] SET landuse = [landuse] WHERE ST_Intersection(geom, GeomFromWKT([wkt_geom], 3857));
    UPDATE [tablename] SET density = [density] WHERE ST_Intersection(geom, GeomFromWKT([wkt_geom], 3857)) WHERE landuse = 'Residential';
    UPDATE [tablename] SET density = NULL WHERE ST_Intersection(geom, GeomFromWKT([wkt_geom], 3857)) WHERE landuse != 'Residential';
    UPDATE [tablename] SET yield = area / 10000 * [density] WHERE ST_Intersection(geom, GeomFromWKT([wkt_geom], 3857));
END;
$$
LANGUAGE plpgsql;

虽然这种方法可以让我免于 运行 从服务器中调用多个嵌套的数据库脚本,但它似乎效率低下并且 Postgres 不会接受 tablename作为一个论点。因此我想知道以下两件事:

  1. 有没有办法根据与提供的几何图形的空间交集创建 table 的子集并迭代每条记录,执行必要的更新?如果是,该功能如何指定?
  2. 我可以提供一个 table 名称作为函数的参数吗?

我不确定继续进行的最佳方式,所以如果有人能告诉我我想做的事情是否可行,如果可以让我开始指定一个函数,我将不胜感激。

干杯。

在 PostgreSQL 中,您可以将 table 名称传递给函数,然后对其进行操作 table,但您必须 EXECUTE a dynamic query, which is inefficient because the query has to be parsed and planned on every function call. If you have only a few tables then it is probably better to just put the command for each of the few tables in one function: the function is bigger but you have to call it only once and the queries can be planned and stored for future usage by the query planner.

根据几何图形之间的交集制作 table 的子集可能不是一件好事。相反,使用你的 UPDATE 命令,它可以被大大优化:

CREATE FUNCTION updateLots(wkt_geom text, lu varchar(25), dens NUMERIC(4,1))
RETURNS void AS $$
BEGIN
  UPDATE t1 SET landuse = lu,
                density = (CASE WHEN lu = 'Residential' THEN dens END), -- ELSE NULL
                yield = area * 0.0001 * dens
  WHERE ST_Intersection(geom, GeomFromWKT(wkt_geom, 3857));

  ...; -- Same for other tables

END; $$ LANGUAGE plpgsql STRICT;

一些注意事项:

另一个潜在的大成本节省是将 wkt_geom 作为 geometry 而不是 text 传递。如果这可以在你的情况下完成,那么你就不必做昂贵的 ST_GeomFromWKT().

因为你想 运行 具有传递 table 名称的函数,你应该使用以下版本:

CREATE FUNCTION updateLots(wkt_geom geometry, tablename varchar(25), lu varchar(25), dens NUMERIC(4,1))
RETURNS void AS $$
BEGIN
  EXECUTE format('
    UPDATE %I SET landuse = %L,
                  density = (CASE WHEN %2$L = ''Residential'' THEN  END),
                  yield = area * 0.0001 * 
    WHERE ST_Intersection(geom, )', tablename, lu)
  USING dens, wkt_geom;
END; $$ LANGUAGE plpgsql STRICT;

在这种情况下,在为每个 table 名称调用此函数一次之前,您绝对应该将 wkt_geom 数据转换为 geometry