从多边形中包含的点集中指定具有最大总体的点

时间:2014-07-28 16:20:50

标签: sql postgresql postgis greatest-n-per-group point-in-polygon

我正在尝试将一个“基于人口的质心”列添加到一系列美国县多边形中,其位置不是基于多边形的地理质心,而是基于填充地理名称的位置人口最多的。例如,我想将箭头指示点(点直径=总体)的几何分配给选定多边形的基于总体的质心列:

enter image description here

我已经测试过这个查询,它会为任何给定的多边形返回正确的几何图形(例如,波士顿的萨福克县):

SELECT g1.the_geom
FROM counties c1
JOIN geonames g1
ON ST_Contains(c1.the_geom, g1.the_geom)
WHERE c1.name = 'Suffolk County, MA'
ORDER BY g1.population DESC
LIMIT 1;

但是,我正在处理~4000个多边形,当我尝试在这样的UPDATE函数中使用查询时,它会无限期地挂起(或者至少比这个特征的数量要长得多):

UPDATE counties
    SET the_geom_popcentroid = (
        SELECT g1.the_geom
        FROM counties c1
        JOIN geonames g1
        ON ST_Contains(c1.the_geom, g1.the_geom)
        ORDER BY g1.population DESC
        LIMIT 1
    );

我在哪里错误地嵌套了这个UPDATE函数?

2 个答案:

答案 0 :(得分:3)

仔细检查:由于外表中的每一行与相关子查询的结果之间没有连接,因此每个 都会获得一个常量值 行。令人费解的是:这不应该,而是非常快。也完全不正确。要修复您的查询:

UPDATE counties c
SET    the_geom_popcentroid = (
        SELECT g.the_geom
        FROM   geonames g
        WHERE  ST_Contains(c.the_geom, g.the_geom)
        ORDER  BY g.population DESC
        LIMIT  1
        );

这会更新所有县。如果一个县根本不应包含任何地理名称,则the_geom_popcentroid设置为NULL。

JOIN语法的替代版本仅更新包含至少一个地理名称的县:

UPDATE counties c
SET    the_geom_popcentroid = sub.the_geom
FROM (
    SELECT DISTINCT ON (c1.pk)
           c1.pk, g1.the_geom
    FROM   counties c1
    JOIN   geonames g1 ON ST_Contains(c1.the_geom, g1.the_geom)
    ORDER  BY c1.pk, g1.population DESC
    ) sub
WHERE c.pk = sub.pk;

pkcounties的主键列(或任何唯一列)。

DISTINCT ON的解释:

不确定哪个更快。尝试在两个ST_Contains()列上使用索引时,ORDER BY third_column LIMIT nthe_geom的组合可能会非常棘手。如果重要,请使用EXPLAIN ANALYZE进行测试。

有时LATERAL JOIN可以帮助说服Postgres使用索引。相关问题:

答案 1 :(得分:1)

在这里使用窗口函数很有帮助:

 WITH max_pop as (
  SELECT DISTINCT c.id as county_id,
    first_value(g.the_geom) OVER (PARTITION BY c.name ORDER BY g.population DESC) as the_geom
  FROM counties c
  JOIN geonames g
    ON ST_Intersects(c.the_geom,g.the_geom)
  )
UPDATE counties
SET pop_center_geom=max_pop.the_geom
FROM max_pop
WHERE counties.id=max_pop.county_id;

我们正在做什么:

按人口下降顺序排列每个县的城市,然后取第一个城市的几何图形和它所在的县的名称。

然后我们使用我们得到的id和几何来更新县表。

我更喜欢这种DISTINCT ON方法,因为对我而言,它更清楚地表明发生了什么,并且更少依赖于"副作用" (因为没有更好的词)。