PostgreSQL函数遍历查询,如何返回表

时间:2019-05-02 00:29:07

标签: postgresql plpgsql sql-function

我有一个带有ID,时间和PostGIS点对象列的表。该表在不同时间为每个ID包含多个点。我想找到一个ID的点集到另一个ID的点集的平均距离,针对同一时间发生的每个点,并求出所有其他ID的点集与该原始ID的点集的平均值。

到目前为止,我具有此功能:

CREATE TYPE score AS (id int, dist float);
CREATE OR REPLACE FUNCTION avgdist(id1 int) RETURNS TABLE (id int, dist float) LANGUAGE plpgsql AS 
$func$ 
    DECLARE 
    scores score; 
    id2 int; 
    set2 record; 
    begin 
        id2:= 0; 
        IF (id1 = id2 ) THEN 
            id2:= 1; 
        END IF; 
        FOR set2 IN 
        SELECT my_table.id, my_table.time, my_table.geom FROM my_table WHERE my_table.id = id2 loop 
            id2:= id2 + 1; 
            CONTINUE WHEN id1 = id2; 
            EXECUTE 'WITH origin AS (SELECT time, id, geom FROM my_table WHERE id = $1)
                SELECT id, avg(ST_Distance(origin.geom, $2)) 
                FROM origin WHERE origin.time = $3 
                group by origin.id 
                ORDER BY id' 
                    INTO scores 
                    USING id1, set2.geom, set2.time; 
        end loop; 
        RETURN; 
    end 
$func$;

使用select * from avgdist(2)调用此函数时,没有得到任何结果,与slect avgdist(2)相同。当我在带有插入值的psql中在自己的execute中运行查询时,我确实得到了结果。

我是第一次在sql中创建函数,所以当该表没有名称时,我并不真正了解如何将分数放入返回表中。而且我似乎无法使用RETURN QUERY,因为我需要返回循环中所有查询的结果。

在此方面的帮助将不胜感激,或者有更好的方法来实现我想要的结果而不会循环?

1 个答案:

答案 0 :(得分:2)

还有更多问题:

  • 子句RETURNS TABLE定义OUT变量。您可以使用这些变量。

    CREATE OR REPLACE FUNCTION foo()
    RETURNS TABLE (r1 int, r2 int)
    -- you don't need aux variables for result
    ...
      r1 := 10; r2 := 10;
      RETURN NEXT;
    
  • EXECUTE INTO只能存储动态查询结果的第一行(或值)。

  • RETURN停止功能评估。您应该使用RETURN NEXTRETURN QUERY

    FOR x, y IN SELECT ..
    LOOP
      -- when only first row of result is interesting
      EXECUTE '..' INTO r1, r2 USING x, y;
      RETURN NEXT;
    END LOOP
    

    或带有RETURN QUERY EXECUTE

    FOR x, y IN SELECT ..
    LOOP
      RETURN QUERY EXECUTE '..' USING x, y;
    END LOOP
    
  • 我不理解您的代码,但是看起来您不需要使用动态SQL-EXECUTE命令。仅当在SQL标识符上有变量时,才需要动态SQL。没有这种情况。同样的情况-为什么使用 CTE WITH子句。不必要-可能产生负面影响(不必要的实现-由PostgreSQL 12修复)。仅使用RETURN QUERY(不使用EXECUTE)并将查询作为查询(而不是字符串)传递。

有关这些命令的文档很好-https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-STATEMENTS-RETURNING