Функция PostgreSQL, повторяющая запрос, как вернуть таблицу - PullRequest
0 голосов
/ 02 мая 2019

У меня есть таблица со столбцом идентификатора, времени и точечного объекта PostGIS.Таблица содержит несколько точек для каждого идентификатора в разное время.Я хочу найти среднее расстояние набора точек одного идентификатора до набора точек другого идентификатора для каждой точки, которая происходит в одно и то же время, и найти это среднее для набора точек всех других идентификаторов по сравнению с набором этого исходного идентификатора.

Пока у меня есть эта функция:

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).Я получаю результаты, когда запускаю запрос внутри команды execute в psql с подключенными значениями.

Я новичок в создании функций в SQL, поэтому я не совсем понимаю, как поместить результаты в таблицу возврата, когда у этой таблицы нет имени.И я не могу использовать RETURN QUERY, так как мне нужно возвращать результаты для всех запросов в цикле.

Помощь по этому вопросу будет принята, или есть лучший способ достичь желаемых результатовбез зацикливания?

1 Ответ

2 голосов
/ 02 мая 2019

Есть еще проблемы:

  • Предложение 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 NEXT или RETURN 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

...