1

Я хочу рассчитать расстояние от адресов до всех улиц на расстоянии 50 метров, используя plpgsql. Я попытался следующие функции:Невозможно выполнить функцию в plpgsql/postgres

Create or Replace Function get_dist(ad geometry, st geometry) 
Returns double precision AS 
$$ 
Begin 
Insert into street(Distance) 
Select ST_Distance(ad.geom, st.geom) from ad 
Left Join st ON ST_DWithin(ad.geom, st.geom, 50.0); 
Return ST_Distance(ad.geom, st.geom); 
End 
$$ 
Language plpgsql volatile; 

Создание функции не дает ошибки, но когда я пытаюсь вызвать его, используя следующую команду:

Select get_dist(ad.geom, st.geom) from ad 
Left Join st ON st.gid = ad.gid; 

я получаю эту ошибку:

ERROR: missing FROM-clause entry for table "ad" 
LINE 1: SELECT ST_Distance(ad.geom, st.geom) 

Может кто-нибудь, пожалуйста, подчеркнуть, что не так с функцией (созданием функции и ее вызовом)?

+0

Пропустить все записи - ad/st или geometry ... В функции - если ad/st - геометрия, то перепишите внутренний выбор ... –

+0

Как выполнить эту функцию без ошибок? Существуют ли в вашей базе данных таблицы 'ad' и' st' (поскольку вы выбираете из них)? Пожалуйста, опишите более подробно, что вы пытаетесь выполнить. –

ответ

1

Для обработки одной строки или обработки строк по одному вы можете использовать предложение SQL RETURNINGINSERT в сочетании с предложением plpgsql INTO. Пример:

Но вы, очевидно, пытается обработать весь набор сразу.

calculate distance from address points to all streets within a distance of 50 meters ...

Используйте подход на основе набора. Много быстрее и чище. Если вы хотите вернуть строки из INSERTдополнительно используйте функцию set-return. Пример:

Вам не нужно будет функцию вообще. Просто этот запрос:

INSERT INTO street(ad_geom, st_geom, distance, traffic_ct) -- any columns in street 
SELECT ad.geom, st.geom, ST_Distance(ad.geom, st.geom), ad.traffic_ct 
FROM ad 
LEFT JOIN st ON ST_DWithin(ad.geom, st.geom, 50.0) 
RETURNING * -- all columns in street 

Я думаю, вы на самом деле не нужно ничего возвращается больше, так как этот запрос делает все, что вы хотели, но я продолжал RETURNING как доказательство концепции. Вы можете просто пропустить его.

Используйте [INNER] JOIN вместо LEFT [OUTER] JOIN, если вы не хотите включать адреса без соответствующей улицы.

The manual about RETURNING in INSERT:

The optional RETURNING clause causes INSERT to compute and return value(s) based on each row actually inserted [...] any expression using the table's columns is allowed. The syntax of the RETURNING list is identical to that of the output list of SELECT . Only rows that were successfully inserted or updated will be returned.

Если нужно обернуть это в функцию plpgsql (также может быть простой функции SQL) - и до сих пор возвращает все строки:

CREATE OR REPLACE FUNCTION insert_neighbours() 
    RETURNS SETOF street AS 
$func$ 
BEGIN 
    RETURN QUERY 
    INSERT INTO street(ad_geom, st_geom, distance, traffic_ct) -- any columns in street 
    SELECT ad.geom, st.geom, ST_Distance(ad.geom, st.geom), ad.traffic_ct 
    FROM ad 
    LEFT JOIN st ON ST_DWithin(ad.geom, st.geom, 50.0) 
    RETURNING *; -- all columns in street 
END 
$func$ LANGUAGE plpgsql; 

Вызов:

SELECT * FROM insert_neighbours(); -- use SELECT * FROM ... ! 

Для простоты I retur n всю строку, но вы также можете вернуть столбцы выбора. See above example.


Creating the function gives no error

Это потому, что PL/PgSQL в настоящее время работает только поверхностные проверки синтаксиса на CREATE FUNCTION. Вы должны фактически выполнить функцию для ее проверки - и убедитесь, что все ветви кода в функциях plpgsql прошли тестирование.

1

Появляется , чтобы хотеть рассчитать расстояние между двумя геометриями, а затем вставить это расстояние в таблицу, если оно меньше 50,0. Функция будет выглядеть так:

CREATE FUNCTION get_dist(ad geometry, st geometry) RETURNS double precision AS $$ 
DECLARE 
    dist double precision; 
BEGIN 
    dist := ST_Distance(ad, st); 
    IF dist < 50.0 THEN 
     INSERT INTO street(Distance) VALUES (dist); 
    END IF; 
    RETURN dist; 
END; 
$$ LANGUAGE plpgsql; 

Однако, я сомневаюсь, что вы действительно хотят. Для начала вставленная строка в таблице street будет назначена distance = dist при вызове функции и выполнении условия, но никаких других свойств (кроме значений по умолчанию) не будет. Что вы действительно хотите не понять из вашего вопроса, но я надеюсь, что вы можете работать с кодом выше, чтобы сделать рабочую функцию.

+0

Спасибо. Это действительно решило мою проблему и именно то, что я хотел. Если я также хочу вернуть геометрию выбранных улиц, которые находятся в 50 метрах, то это можно сделать, изменив вышеприведенную функцию или мне нужно написать отдельную функцию? –

+0

Проблема в том, что вы ничего не выбираете из таблицы 'street'. Или 'st' так же, как' street'? Какие еще данные вы хотите хранить в таблице 'street'? – Patrick

+0

Я хотел хранить другие данные, такие как геометрия выбранных улиц (геометрия), расстояние между адресами до выбранных улиц (помогаемое вами выше) и количество траффика w.r.t. адресная таблица. Должен ли я писать отдельную функцию для каждого из них? Да, ST - это уличный стол, а ad - таблица адресов. –