【问题标题】:Distance calculation in a trigger postgresql触发器postgresql中的距离计算
【发布时间】:2018-09-11 12:36:30
【问题描述】:

我有两个表“modulo1_cella”和“modulo2_campionamento”。

第一个“modulo1_cella”包含多边形,而后者“modulo2_campionamento”包含点(样本)。现在,我需要为每个多边形分配最近的样本,以及采样器本身的标识。

                                           Table "public.modulo1_cella"
      Column       |       Type        |                            Modifiers
-------------------+-------------------+------------------------------------------------------------------
 cella_id          | integer           | not null default nextval('modulo1_cella_cella_id_seq'::regclass)
 nome_cella        | character varying |
 geometria         | geometry          |
 campione_id       | integer           |
 dist_camp         | double precision  |

                                       Table "public.modulo2_campionamento"
          Column          |            Type             |                                    Modifiers
--------------------------+-----------------------------+----------------------------------------------------------------------------------
 campione_id              | integer                     | not null default nextval('modulo2_campionamento_aria_campione_id_seq'::regclass)
 x_campionamento          | double precision            |
 y_campionamento          | double precision            |
 codice_campione          | character varying(10)       |
 cella_id                 | integer                     |
 geometria                | geometry(Point,4326)        |

我正在寻找一个 INSERT/UPDATE 触发器,它为“modulo1_cella”表的每一行(即每个多边形)返回:

  • 最近的样本,“campione_id”;
  • 对应的距离,“dist_camp”。

我创建了一个有效的查询,但我无法将其转换为触发器。

CREATE TEMP TABLE TemporaryTable 
(
    cella_id int,
    campione_id int,
    distanza double precision 
);

INSERT INTO TemporaryTable(cella_id, campione_id, distanza)
SELECT 
DISTINCT ON (m1c.cella_id) m1c.cella_id, m2cmp.campione_id, ST_Distance(m2cmp.geometria::geography, m1c.geometria::geography)  as dist

FROM modulo1_cella As m1c, modulo2_campionamento As m2cmp  
WHERE ST_DWithin(m2cmp.geometria::geography, m1c.geometria::geography, 50000) 
ORDER BY m1c.cella_id, m2cmp.campione_id, ST_Distance(m2cmp.geometria::geography, m1c.geometria::geography);

UPDATE modulo1_cella as mc
SET campione_id=tt.campione_id, dist_camp=tt.distanza
from TemporaryTable as tt
where tt.cella_id=mc.cella_id;

DROP TABLE TemporaryTable;

有什么帮助吗?提前谢谢你。

【问题讨论】:

  • 如果我可以建议 - 不要在触发器上做这样的事情。当数据库中的触发器很少时,触发器在开始时似乎是一件好事。但是随着时间的推移,当您拥有数十个、数百个甚至数千个应用程序时,您就会失去对应用程序中正在发生的事情的控制。只需创建一个用于向 cella 表添加/更新新记录的函数。当您想创建新的细胞或更新现有的细胞时调用它。您将完全控制正在发生的事情,而无需一连串的触发器。
  • 另外,当您添加新多边形或更新现有多边形时会发生什么?你不应该用新数据重新计算你的细胞吗?

标签: sql postgresql postgis


【解决方案1】:

首先,如果“geometria”不是geography,而是geometry,则应将其设为geography 类型。

ALTER TABLE modulo2_campionamento
  ALTER COLUMN geometria
  SET DATE TYPE geography(POINT 4326)
  USING (geometria::geography);

ALTER TABLE modulo1_cella
  ALTER COLUMN geometria
  SET DATA TYPE geography(4326)
  USING (geometria::geography);

现在,我需要为每个多边形分配最近的样本,以及采样器本身的标识。

您通常不会这样做,因为使用 KNN search anyway. 找到最近的样本非常快

CREATE INDEX ON modulo1_cella USING gist (geometria);
CREATE INDEX ON modulo2_campionamento USING gist (geometria);
VACUUM FULL ANALYZE modulo1_cella;
VACUUM FULL ANALYZE modulo2_campionamento;

SELECT *
FROM modulo1_cella As m1c
CROSS JOIN LATERAL (
  SELECT *
  FROM modulo2_campionamento As m2cmp
  WHERE ST_DWithin(m2cmp.geometria, m1c.geometria, 50000)
  ORDER BY m2cmp.geometria <-> m1c.geometria, 
    m1c.cella_id,
    m2cmp.campione_id
  FETCH FIRST ROW ONLY
) AS closest_match

这比您编写的 DISTINCT ON 查询快

如果速度足够快,我建议使用VIEW。如果这还不够快,我建议使用MATERIALIZE VIEW。如果它仍然不够快,那么您的负载非常小,可能值得研究带有触发器的解决方案。但只有那时。

【讨论】:

    猜你喜欢
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多