1

Ich möchte Entfernung von Adreßpunkten zu allen Straßen innerhalb einer Entfernung von 50 Metern mit plpgsql berechnen. Ich habe die folgende Funktion versucht:Kann die Funktion in plpgsql/postgres nicht ausführen

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; 

die Funktion Erstellen gibt keinen Fehler, aber wenn ich versuche, es zu nennen diesen Befehl:

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

ich diesen Fehler:

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

Kann jemand bitte hervorheben, was mit der Funktion falsch ist (die Funktion verursachen und sie nennen)?

+0

Pass ganze Datensätze - ad/st, oder Geometrie ... In der Funktion - wenn ad/st ist Geometrie - dann neu schreiben inneren wählen ... –

+0

Wie können Sie diese Funktion ausführen, ohne Fehler zu bekommen? Gibt es in Ihrer Datenbank Tables "ad" und "st" (da Sie aus diesen auswählen)? Bitte beschreiben Sie genauer, was Sie zu erreichen versuchen. –

Antwort

1

Für die Verarbeitung einer einzelnen Zeile oder die sequentielle Verarbeitung von Zeilen können Sie die Klausel RETURNING von INSERT kombiniert mit der Klausel plpgsql INTO verwenden. Beispiel:

Aber Sie versuchen offensichtlich auf einmal eine ganze Reihe zu verarbeiten.

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

Verwenden Sie einen Set-basierten Ansatz. Viel schneller und sauberer. Wenn Sie Zeilen vom INSERTzusätzlich zurückgeben möchten, verwenden Sie eine Set-Return-Funktion. Beispiel:

Sie würden nicht brauchen überhaupt eine Funktion. Nur diese Abfrage:

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 

Ich denke, Sie nicht wirklich brauchen nichts mehr zurück, da diese Abfrage alle tut man wollte, aber ich hielt RETURNING als Proof of Concept. Sie können es einfach überspringen.

Verwenden Sie [INNER] JOIN anstelle von , wenn Sie keine Adressen ohne übereinstimmende Straße hinzufügen möchten.

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.

Wenn Sie Notwendigkeit diese in eine plpgsql Funktion zu wickeln (könnte auch eine einfache SQL-Funktion sein) - und zurück nach wie vor alle Zeilen:

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; 

Call:

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

Zur Vereinfachung gehe ich zurück n die ganze Zeile, aber Sie können auch ausgewählte Spalten zurückgeben. See above example.


Creating the function gives no error

Das ist, weil PL/pgSQL derzeit nur oberflächliche Syntaxprüfungen auf CREATE FUNCTION läuft. Sie müssen die Funktion tatsächlich ausführen, um sie zu testen - und sicherstellen, dass alle Zweige des Codes in plpgsql-Funktionen getestet werden.

1

Was Sie erscheinen zu wollen ist, einen Abstand zwischen zwei Geometrien zu berechnen und dann den Abstand in einer Tabelle einfügen, wenn es als 50,0 ist. Die Funktion würde wie folgt sein:

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; 

Ich bezweifle jedoch, dass Sie wirklich das wollen. Für den Anfang wird die eingefügte Zeile in der Tabelle streetdistance = dist zugeordnet, wenn die Funktion aufgerufen wird und die Bedingung erfüllt ist, aber keine anderen Eigenschaften (außer Standardwerte). Was Sie wirklich wollen ist nicht klar aus Ihrer Frage, aber ich hoffe, Sie können aus dem obigen Code arbeiten, um eine funktionierende Funktion zu machen.

+0

Danke. Es löste tatsächlich mein Problem und genau das, was ich wollte. Wenn ich auch die Geometrie ausgewählter Straßen, die sich in 50 Metern Entfernung befinden, zurückgeben möchte, kann dies durch Änderung der obigen Funktion geschehen oder muss ich eine separate Funktion schreiben? –

+0

Das Problem hier ist, dass Sie nichts aus der 'street' Tabelle auswählen. Oder ist "st" dasselbe wie "street"? Welche anderen Daten möchten Sie in der Tabelle "Straße" speichern? – Patrick

+0

Ich wollte andere Daten wie Geometrie der ausgewählten Straßen (Geom), Entfernung zwischen Adresse zu ausgewählten Straßen (von Ihnen oben unterstützt) und Verkehrszählungen w.r.t speichern. Adresstabelle. Muss ich für jedes von ihnen eine separate Funktion schreiben? Ja, ST ist die Straßentabelle, während die Ad-Adresstabelle ist. –