无法执行 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 函数中的所有代码分支都得到测试。