我正在尝试将一个“基于人口的质心”列添加到一系列美国县多边形中,其位置不是基于多边形的地理质心,而是基于填充地理名称的位置人口最多的。例如,我想将箭头指示点(点直径=总体)的几何分配给选定多边形的基于总体的质心列:
我已经测试过这个查询,它会为任何给定的多边形返回正确的几何图形(例如,波士顿的萨福克县):
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函数?
答案 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;
pk
是counties
的主键列(或任何唯一列)。
DISTINCT ON
的解释:
不确定哪个更快。尝试在两个ST_Contains()
列上使用索引时,ORDER BY third_column LIMIT n
与the_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方法,因为对我而言,它更清楚地表明发生了什么,并且更少依赖于"副作用" (因为没有更好的词)。