PL / PGSQL总是返回数组或数组列表

时间:2015-08-06 20:38:24

标签: sql postgresql plpgsql nearest-neighbor

给出简单的pl / pgsql函数:

CREATE OR REPLACE FUNCTION foo (point geometry
                              , OUT _street text
                              , OUT _gid int
                              , OUT distance real)
AS $$
BEGIN 

    SELECT min(distance(point,geom)) as dist, gid, name into distance, _gid, _street
    from streets 
    where geometria && Expand(point,0.001) group by gid, name order by dist limit 1;

END;
$$ LANGUAGE plpgsql;

导致类似于:

 geobase=# select foo(GeomFromText('POINT(-99.124191496999 19.3490666368031)',4326));
                      foo                      
 -------------------------------------------------
 ("PASEO DE LOS FRAMBOYANES",345483,0.000118338)

哪个好,除了我希望更类似于此的事实:

          _street         |  _gid  |  distance     
--------------------------+--------+-------------
 PASEO DE LOS FRAMBOYANES | 345483 | 0.000118338

我尝试过使用RETURN子句的变体,将其定义为rowtype,record和even table,但我总是得到一个元组或数组,如示例中所示。关于如何以类似于表格的方式获得结果的任何线索?

2 个答案:

答案 0 :(得分:1)

试试select * from foo(GeomFromText('POINT(-99.124191496999 19.3490666368031)',4326));

答案 1 :(得分:0)

问题已被多次回答。要分解返回的行类型,请使用

SELECT * FROM foo( ... );

喜欢这里:

但还有更多。

您的函数具有较少混淆语法,不易出错且简化:

CREATE OR REPLACE FUNCTION foo (_point geometry)
  RETURNS TABLE (street text, gid int, distance real) AS
$func$
BEGIN

RETRUN QUERY 
SELECT s.name, s.gid, distance(_point, s.geom)
FROM   streets s
WHERE  s.geometria && expand(_point, 0.001)
ORDER  BY 3
LIMIT  1;

END
$func$ LANGUAGE plpgsql;

由于您有ORDER BY ... LIMIT 1,因此您根本不需要min()GROUP BY

注意我如何对所有列进行表限定以避免命名冲突。

有一个微妙的区别 :如果查询找到 没有行 ,您的原始文件会返回一行为NULL而值,而我的函数实际上不返回任何行。通常情况下,您会想要后者。

与等效的简单SQL函数相同:

CREATE OR REPLACE FUNCTION foo (_point geometry)
  RETURNS TABLE (street text, gid int, distance real) AS
$func$
SELECT s.name, s.gid, distance(_point, s.geom)
FROM   streets s
WHERE  s.geometria && expand(_point, 0.001)
ORDER  BY 3
LIMIT  1
$func$ LANGUAGE sql;

但是对于大桌来说效率不高。您对PostGis中的 KNN(k-最近邻居)搜索感兴趣