Расчет расстояния в триггере postgresql - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть две таблицы "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;

Любая помощь? Заранее спасибо.

1 Ответ

0 голосов
/ 11 сентября 2018

Во-первых, если "геометрия" не 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 в любом случае.

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.Если он все еще недостаточно быстр, у вас очень нишевая нагрузка, и, возможно, стоит изучить решение с помощью триггеров.Но только тогда.

...