无法执行 plpgsql/postgres 中的函数

Posted

技术标签:

【中文标题】无法执行 plpgsql/postgres 中的函数【英文标题】:Unable to execute the function in plpgsql/postgres 【发布时间】:2016-06-20 09:02:53 【问题描述】:

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

有人可以突出显示函数的问题(创建函数并调用它)吗?

【问题讨论】:

传递整个记录 - ad / st, or geometry... 在函数中 - 如果 ad/st 是几何 - 然后重写内部选择... 如何执行这个函数而不出错?您的数据库中是否有表adst(因为您正在从中选择)?请更详细地描述您要完成的工作。 【参考方案1】:

对于单行或一行一行的处理,可以使用INSERT的SQLRETURNING子句结合plpgsqlINTO子句。示例:

Get default serial value after INSERT inside PL/pgSQL

但你显然是想同时处理一整套。

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

使用基于集合的方法。 更多更快更干净。如果您想从INSERT 返回行另外请使用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

我猜您实际上不再需要返回任何内容,因为此查询可以满足您的所有需求,但我保留了 RETURNING 作为概念证明。你可以跳过它。

如果您不想包含没有匹配街道的地址,请使用 [INNER] JOIN 而不是 LEFT [OUTER] JOIN

The manual about RETURNING in INSERT:

可选的RETURNING 子句导致INSERT 计算并返回 基于实际插入的每一行的值 [...] 任何表达式 允许使用表的列。 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 函数中的所有代码分支都经过测试。

【讨论】:

【参考方案2】:

似乎想要的是计算两个几何图形之间的距离,然后将该距离插入表格中(如果它小于 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,但没有其他属性(任何默认值除外)。您真正想要什么并不清楚您的问题,但我希望您可以根据上面的代码来制作一个有效的功能。

【讨论】:

谢谢。它确实解决了我的问题,也正是我想要的。如果我还想返回 50 米内选定街道的几何图形,那么可以通过修改上述函数来完成,还是必须编写一个单独的函数? 这里的问题是您没有从street 表中选择任何内容。还是ststreet 一样?您还想在表street 中存储哪些其他数据? 我想存储其他数据,例如所选街道的几何形状 (geom)、地址与所选街道之间的距离(由您在上面提供帮助)和交通流量 w.r.t.地址表。我是否必须为每个人编写单独的函数?是的,ST 是街道表,而广告是地址表。

以上是关于无法执行 plpgsql/postgres 中的函数的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE有没有判断一个字串里面包含令一个字串的函式

javaScript之this全面解析

关于对《运动面层性能测试方法 第1部分:规格》等两项行业标准征求意见的函

住建部关于同意北京市开展建设工程人工智能审图试点的函

JavaScript计时事件

请教:用迅为4412开发板开机时卡在Android静止画面