需要一个查询,以根据旧的几何列值将其更改为新值

时间:2014-07-21 17:08:10

标签: postgresql postgis geodjango

我有一个GeoDjango数据库表,如下所示:

# \d spirits_spirit
        Table "public.myapp_mymodel"
  Column  |           Type        |    Modifiers                          
----------+-----------------------+------------------
 id       | integer               | not null default nextval('spirits_spirit_id_seq'::regclass)
 activity | integer               | not null
 location | geography(Point,4326) | 

当然还有更多的列,但这些是唯一可能相关的列。我还应该指出,这个表有可能非常大,在数十万甚至数百万行的范围内。

现在,我想要做的是改变匹配activity = 3或其他任何对象的位置。该位置需要距离当前位置n米,其中n是一个介于10和100之间的随机数。

实际上,我希望我的对象移动,我想在单个UPDATE查询中执行此操作,而不是在Python中循环所有内容...除非有人认为这样做是一个坏主意。

对我来说问题是我不知道该怎么做:

UPDATE
  myapp_mymodel
SET
  location.x = location + 0.5,
  location.y = location + 0.2
WHERE
  activity = 3;

...或者没有循环遍历所有内容,创建对象的实例,在Python中进行调整然后执行.save()。我对PostGIS如何工作的把握目前仅限于GeoDjango如何通过它的ORM隐藏所有东西,所以我在这里问:

这可能吗?这甚至是个好主意吗?在Python循环中实现这一切真的更好吗?

1 个答案:

答案 0 :(得分:1)

在我看来,最好在数据库级别进行数据更新,而不是将其带到客户端 - 这是数据库优化的事情之一。我不确定你是如何定义移动x和y的随机量,但你可以使用的一件事是ST_Translate,它会在x和y方向上移动一个几何体。所以在你的情况下,例如,

UPDATE
  myapp_mymodel
SET
  location = ST_Transform(ST_Translate(ST_Transform(location::geometry,
               3857), random()*10, random()*10) ,4326)
WHERE
  activity = 3;

其中x和y在0到10之间移动一些数字,并且几何体就地更新。这看起来比它更混乱。基本上,有四个步骤。

  1. 您将位置转换为几何图形,因为ST_Translate函数不适用于地理位置。
  2. 使用ST_Transform将纬度/经度(EPSG:4326)转换为以米为单位的值,在本例中为球形墨卡托(EPSG:3857)。这是一个很好的选择,因为它是一个覆盖全球的投影。
  3. 使用ST_Translate按x / y方向转换几米。
  4. 再次使用ST_Transform再次回到lat / lon,(EPSG:4326)。
  5. <强>买者即可。球形墨卡托(3857)由谷歌开发,以投影仪表覆盖全球。它使投影的数学非常容易处理(因为它假设为球形地球),但确实受到尺度/距离扭曲的影响,你从赤道得到的距离越远。如果您想要以米为单位进行极其精确的移动,则需要使用不同的坐标系。

    注意:EPSG代表欧洲石油调查组,是管理空间参考系统的组织,例如4326或3857.这些在Postgis中称为SRID,空间参考ID。

    注2 。您也可以使用度数的ST_Translate,但是您在x和y方向上的移动需要以度为单位表示。这将避免双重ST_Transform,但意味着添加另一个计算以将米转换为度数。

    我已经在Postgres / Postgis上对数百万行进行了这种性质的更新而没有任何问题。唯一需要注意的是,您有足够的空间来存储更改,因为更新是单个事务,如果出现问题则需要回滚。根据活动字段中的值范围,在获取活动索引时可能也值得(解释是你的朋友)。