如何根据这些 table 中的空间关系几何将数据从 table 设置到另一个

How can I set data from on table to another according spatial relation geometries in these tables

我有两个 table 有数据。关于这些 table 中数据之间的空间关系,我需要将数据 building_h 从一个 table 设置到另一个。源 table 中的空间数据是多边形类型,目标 table 中的空间数据是点。我查询了相交的点和多边形。它很好用。但是有些点不与多边形相交。我的想法是为这些点中的每一个定义最接近的多边形并从中获取 building_h 值。为此,我编写了函数,该函数采用点的 id 和 returns building_h 值。并且在测试中运行正常。

CREATE OR REPLACE FUNCTION closest_pol(int4)
RETURNS NUMERIC 
AS
$$
DECLARE
    retVal NUMERIC;
BEGIN
    SELECT bgs.building_h INTO retVal
                FROM buildings_geoalert_spgg bgs, building_from_landuse_spgg bfl 
                WHERE ST_INTERSECTS(bgs.geom, ST_BUFFER(bfl.geom_centr, 0.0006,'quad_segs=8')) AND bfl.id = 
                ORDER BY ST_INTERSECTION(bgs.geom, ST_BUFFER(bfl.geom_centr, 0.0006,'quad_segs=8')) ASC 
                LIMIT 1;
RETURN retVal;
END;
$$
LANGUAGE plpgsql 
   STABLE 
RETURNS NULL ON NULL INPUT;

但是当我 运行 查询整个 table 时,它会永远执行……(约 3000 行具有 NULL 值)。持续了几个小时才停止。

UPDATE building_from_landuse_spgg AS bfl SET 
    building_h = (SELECT closest_pol(bfl.id))
    WHERE bfl.building_h IS NULL;

你知道我做错了什么吗?

在您的 WHERE 子句中,您使用 ST_Intersects 和在查询时创建的 0.006 缓冲区。考虑对你的这个缓冲区使用部分 gist 索引(如果出于某种原因你必须使用它们):

CREATE INDEX idx_buffer ON building_from_landuse_spgg USING gist (ST_Buffer(geom_centr, 0.0006,'quad_segs=8'));

我认为您不需要为此使用函数,因为您可以将函数内部的查询用作 UPDATE 语句中的子查询。但是如果你有理由坚持这个功能,你可以去掉 SELECT 来调用它:

UPDATE building_from_landuse_spgg 
SET building_h = closest_pol(id)
WHERE building_h IS NULL;

编辑:正如@JGH 正确提到的(见评论),使用缓冲区的效率低于简单地使用 ST_DWithin。因此,如果您负担得起,请在 WHERE 子句中使用的几何图形中创建一个索引 ..

CREATE INDEX idx_landuse_geom_centr ON building_from_landuse_spgg USING gist (geom_centr);
CREATE INDEX idx_geoalert_geom ON buildings_geoalert_spgg USING gist (geom);

.. 以及部分索引 building_h 会加快速度,因为您只对 NULL 记录感兴趣:

CREATE INDEX idx_landuse_building_h ON building_from_landuse_spgg (building_h) 
WHERE building_h IS NULL;

或者,如果您更喜欢更广泛的索引,但仍将 NULL 值放在 前 class ..

CREATE INDEX idx_landuse_building_h ON building_from_landuse_spgg 
  (building_h NULLS FIRST);

也许可以考虑将函数代码放在子查询中,例如

UPDATE building_from_landuse_spgg AS bfl 
SET building_h = (
  SELECT bgs.building_h 
  FROM   buildings_geoalert_spgg bgs 
  WHERE  ST_DWithin(bgs.geom, bfl.geom_centr, 0.0006)
  ORDER BY ST_Distance(bgs.geom, bfl.geom_centr) ASC LIMIT 1)
WHERE bfl.building_h IS NULL;

延伸阅读: