无法在plpgsql / postgres中执行该函数

时间:2016-06-20 09:02:53

标签: postgresql sql-insert plpgsql set-returning-functions sql-returning

我想使用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)

有人可以突出显示该功能有什么问题(创建功能并调用它)?

2 个答案:

答案 0 :(得分: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,但没有其他属性(除了任何默认值)。您的真正想要的东西在您的问题中并不清楚,但我希望您可以使用上面的代码来完成工作。

答案 1 :(得分:1)

为了处理单行或逐行处理行,您可以使用RETURNING的SQL INSERT子句与plpgsql INTO子句相结合。例如:

但你显然是想立刻处理一整套。

  

在50米范围内计算从地址点到 所有街道 的距离......

使用基于集合的方法。 很多更快更清洁。如果您想要再次从INSERT 返回行,请使用设置返回功能。例如:

根本不需要功能。只是这个查询:

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:

  

可选的RETURNING子句导致INSERT计算并返回   基于实际插入任何表达式的每一行的值(s)   允许使用表格的列。 RETURNING的语法   list与SELECT的输出列表相同。只有行   已成功插入或更新的内容将被退回。

如果你需要将它包装成一个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 ... !

为简单起见,我返回整行,但您也可以返回选择列。 See above example.

  

创建函数不会出错

那是因为PL / pgSQL目前只在CREATE FUNCTION上运行表面语法检查。您必须实际执行该函数来测试它 - 并确保测试plpgsql函数中的所有代码分支。