无法执行 plpgsql/postgres 中的函数
Unable to execute the function in plpgsql/postgres
我想用plpgsql计算地址点到50米范围内所有街道的距离。我尝试了以下功能:
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)
有人可以突出显示函数有什么问题(创建函数并调用它)吗?
您似乎想要的是计算两个几何之间的距离,然后将该距离插入 table(如果它小于 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;
但是,我怀疑您真的想要那个。对于初学者来说,当函数被调用并且满足条件时,table street
中插入的行将被分配 distance = dist
,但没有其他属性(任何默认值除外)。你真正想要什么从你的问题中不清楚,但我希望你能从上面的代码中得到一个工作函数。
要处理单行或逐行处理,可以使用INSERT
的SQLRETURNING
子句结合plpgsql的INTO
子句。示例:
但是你显然是想一次处理一整套。
calculate distance from address points to all streets within a distance of 50 meters ...
使用基于集合的方法。 很多 更快更干净。如果您想 INSERT
中的 return 行,另外 使用 set-returning 函数 。示例:
- Return a query from a function?
你根本不需要函数。只是这个查询:
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
我想您实际上不再需要任何 returned,因为这个查询可以满足您的所有需求,但我保留了 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 函数)-并且仍然 return 所有行:
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 ... !
为简单起见,我 return 整行,但您也可以 return select 列。 See above example.
Creating the function gives no error
那是因为 PL/pgSQL 目前只对 CREATE FUNCTION
运行表面语法检查。您必须实际执行函数来测试它 - 并确保 plpgsql 函数中的所有代码分支都得到测试。
我想用plpgsql计算地址点到50米范围内所有街道的距离。我尝试了以下功能:
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)
有人可以突出显示函数有什么问题(创建函数并调用它)吗?
您似乎想要的是计算两个几何之间的距离,然后将该距离插入 table(如果它小于 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;
但是,我怀疑您真的想要那个。对于初学者来说,当函数被调用并且满足条件时,table street
中插入的行将被分配 distance = dist
,但没有其他属性(任何默认值除外)。你真正想要什么从你的问题中不清楚,但我希望你能从上面的代码中得到一个工作函数。
要处理单行或逐行处理,可以使用INSERT
的SQLRETURNING
子句结合plpgsql的INTO
子句。示例:
但是你显然是想一次处理一整套。
calculate distance from address points to all streets within a distance of 50 meters ...
使用基于集合的方法。 很多 更快更干净。如果您想 INSERT
中的 return 行,另外 使用 set-returning 函数 。示例:
- Return a query from a function?
你根本不需要函数。只是这个查询:
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
我想您实际上不再需要任何 returned,因为这个查询可以满足您的所有需求,但我保留了 RETURNING
作为概念证明。你可以跳过它。
如果您不想包含没有匹配街道的地址,请使用 [INNER] JOIN
而不是 LEFT [OUTER] JOIN
。
The manual about RETURNING
in INSERT
:
The optional
RETURNING
clause causesINSERT
to compute and return value(s) based on each row actually inserted [...] any expression using the table's columns is allowed. The syntax of theRETURNING
list is identical to that of the output list ofSELECT
. Only rows that were successfully inserted or updated will be returned.
如果您需要将其包装到一个 plpgsql 函数中(也可以是一个简单的 SQL 函数)-并且仍然 return 所有行:
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 ... !
为简单起见,我 return 整行,但您也可以 return select 列。 See above example.
Creating the function gives no error
那是因为 PL/pgSQL 目前只对 CREATE FUNCTION
运行表面语法检查。您必须实际执行函数来测试它 - 并确保 plpgsql 函数中的所有代码分支都得到测试。