有没有办法在一个空间查询中设置多个列值?

问题描述 投票:1回答:1

我正在使用PostGIS的属性与点关联。ST_DWIthin().

UPDATE scratch.intersections AS i
SET legs = (
    SELECT COUNT(r.geom)
    FROM received.streets r
    WHERE ST_DWithin(i.geom, r.geom, 2));

UPDATE scratch.intersections AS i
SET streets = (
    SELECT ARRAY_AGG(DISTINCT r.NAME ORDER BY r.NAME) 
    filter (WHERE r.NAME IS NOT NULL)
    FROM received.streets r
    WHERE ST_DWithin(i.geom, r.geom, 2));

似乎应该可以用一个空间查询更新多列,但我想不出一种结构化的方法,因为我每次只能更新一列。

有没有办法把这两个查询变成一个查询,只需要一个空间计算?

如果做一个 INNER JOIN 创建一个新的临时表,在某点的2以内的每条线都有一条记录,然后在该表上设置数值?描述,这听起来效率较低,因为性能的 ST_DWithin() 使用索引并不可怕。

postgresql postgis spatial
1个回答
2
投票

可以在一个语句中用括号括起多个列来更新它们

UPDATE myTable
SET (a,b) = (
  select c,d 
  from anotherTable 
  WHERE st_dwithin(mytable.geom, anotherTable.geom,2)
);

2
投票

JGH提供了一个聪明的方法来 UPDATE 从一个(相关的)子查询中同时查询多个列。从Postgres 9.5开始可以实现。然而,有相当大的缺点。

该表单更新了表中的每一行 无条件. 你必须重复计算在 WHERE 子句来有条件地做,这将违背只做一次的目的。

在PostgreSQL的MVCC模型中 UPDATE 基本上意味着要写一个新版本的完整行,臃肿的表和索引。本身就很贵,但也造成了很多额外的工作,对 VACUUM - 和或性能下降,如果你不能或不清理。请看

要么你真的想更新每一行,那么基本就可以了。虽然,如果你不受并发负载或表的内部引用(视图、FK......)的约束,可以考虑写一个新表代替。通常整体上比较便宜。

但是,有些(或者说大部分?)行可能已经是最新的了。那么这就是一个 巨大的浪费. 而是考虑。

UPDATE scratch.intersections AS i
SET    legs    = r.legs  
     , streets = r.streets
FROM   scratch.intersections x
JOIN   LATERAL (
   SELECT count(*) AS legs  -- assuming r.geom is NOT NULL
        , array_agg(DISTINCT s.NAME ORDER BY s.NAME)
                    FILTER (WHERE s.NAME IS NOT NULL) AS streets
   FROM   received.streets s
   WHERE  ST_DWithin(x.geom, s.geom, 2)
   ) r ON x.legs    IS DISTINCT FROM r.legs
       OR x.streets IS DISTINCT FROM r.streets 
WHERE i.id = x.id;  -- id being the PK (or at least UNIQUE)

这不会触及那些没有实际变化的行。

我们需要额外的 scratch.intersectionsFROM 条款,以允许 LATERAL 连接。但是我们在应用更新之前,先消除所有没有变化的行--这样就为每一条已经更新的行节省了大部分工作。好吧,由于子查询的成本比较高,也许不需要了 的工作。但通常情况下,实际的写操作比计算新的值要贵得多。

这和你最后一段的想法很接近。但是不用创建临时表,效率更高,而且还可以节省空写。

而且如果你只需要更新可能受影响的行,在 intersections 换了几行 streets.geom,还有更多的优化潜力,还。不去,似乎不在这个问题的范围内。

相关的。

© www.soinside.com 2019 - 2024. All rights reserved.