Запрос не имеет назначения для данных результата в функции PostgreSQL

avatar
Rogelio Fernandez Aybar
1 июля 2021 в 19:42
88
1
1

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

query has no destination for result data

это мой код postgresql:

CREATE OR REPLACE FUNCTION teltonika_funelement(
    raw character varying,
    tipo integer)
    RETURNS TABLE(id integer, nombre character varying, value1 character varying) 
    LANGUAGE 'plpgsql'

AS $BODY$
DECLARE     i     INT=1;
            y     INT=1;
            Len1  INT;
    ---------------------------------------------------------------------------
    
BEGIN

     CREATE TEMP TABLE Elements(ID Integer, Nombre CHARACTER VARYING, Value2 CHARACTER VARYING);

    
    IF Tipo=1 THEN
    
        Len1    := LENGTH(Raw)/4;

        WHILE i<=Len1
        LOOP
            INSERT INTO Elements
            SELECT
                 hex_to_int(SUBSTRING(Raw FROM y FOR 2))
                ,NULL
                ,SUBSTRING(Raw FROM y+2 FOR 2);

                 y  :=  y+4;

                 i  :=  i+1;
        END LOOP;
    END IF;
    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    IF Tipo = 2 THEN 
    
        Len1 := LENGTH(Raw)/6;
        
        WHILE i<=Len1
        LOOP
            INSERT INTO Elements
            SELECT
                 hex_to_int(SUBSTRING(Raw FROM y FOR 2))
                ,NULL
                ,SUBSTRING(Raw FROM y+2 FOR 4);

                y := y+6;

                i := i+1;
        END LOOP;
    END IF;
    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    IF Tipo = 4 THEN
    
        Len1 := LENGTH(Raw)/10;
        
        WHILE i<=Len1
        LOOP
            INSERT INTO Elements
            SELECT
                 hex_to_int(SUBSTRING(Raw FROM y FOR 2))
                ,NULL
                ,SUBSTRING(Raw FROM y+2 FOR 8);

                y := y+10;

                i := i+1;
        END LOOP;
    END IF;
    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    ---------------------------------------------------------------------------
    IF Tipo = 8 THEN
    
        Len1 := LENGTH(Raw)/18;
        
        WHILE i<=Len1
        LOOP
            INSERT INTO Elements
            SELECT
                 hex_to_int(SUBSTRING(Raw FROM y FOR 2))
                ,NULL
                ,SUBSTRING(Raw FROM y+2 FOR 16);

                y := y+18;

                i := i+1;
        END LOOP;
    END IF;
    ---------------------------------------------------------------------------

    SELECT
         E.ID
        ,PropertyName
        ,CASE
            WHEN (TypeParser = 'INT' AND Active=1) THEN (hex_to_int(Value2):: VARCHAR)
            WHEN (TypeParser = 'DECIMAL(18,1)/1000' AND Active=1)   THEN ((hex_to_int(Value2)/1000)::VARCHAR)
         ELSE 
            Value2
         END Value1
    FROM Elements E
    LEFT JOIN Teltonika_Tbl_ElementsConf TE ON TE.PropertyID=E.ID;
END;
$BODY$;

ALTER FUNCTION public.teltonika_funelement(character varying, integer)
    OWNER TO postgres;

это сообщение об ошибке:

query has no destination for result data 

Я не могу найти причину ошибки. Я пытался изменить возврат следующим образом:

RETURNS TEXT AS 

Как я могу это решить, я очень ценю вашу помощь

Источник
Adrian Klaver
1 июля 2021 в 20:21
3

Измените SELECT E.ID ... на RETURN QUERY SELECT E.ID... согласно документам RETURN TABLE

Rogelio Fernandez Aybar
1 июля 2021 в 21:36
1

Я уже внес изменение, это отношение сообщения об ошибке "элементы" уже существует

Adrian Klaver
1 июля 2021 в 22:05
4

Либо добавьте DROP TABLE IF EXISTS elements непосредственно перед CREATE TEMP TABLE Elements ..., либо используйте ON COMMIT DROP в CREATE TEMP TABLE ... в документах здесь CREATE TABLE.

Rogelio Fernandez Aybar
2 июля 2021 в 16:48
0

Спасибо, Адриан

Ответы (1)

avatar
Jim Jones
2 июля 2021 в 06:05
1

Непустая функция ожидает RETURN, соответствующую типу данных (или структуре), объявленному в RETURNS. В вашем случае таблица, содержащая integer и два character varying. Взгляните на следующую тестовую функцию, которая возвращает таблицу со столбцами int и text:

.
CREATE OR REPLACE FUNCTION myfunc(int)
RETURNS TABLE(val int, txt text)  LANGUAGE 'plpgsql'
AS $$
BEGIN
  CREATE TEMPORARY TABLE tmp(id int,res text) ON COMMIT DROP;

  IF $1=0 THEN 
    INSERT INTO tmp VALUES ($1,'Invalid');
  ELSE 
    FOR i IN 1..$1 LOOP
     INSERT INTO tmp VALUES (i,'txt '||i);
    END LOOP;
  END IF;

  RETURN QUERY SELECT id,res FROM tmp;
END;
$$;

Тест

SELECT * FROM myfunc(2);
 val |  txt  
-----+-------
   1 | txt 1
   2 | txt 2
(2 rows)

Демо: db<>fiddle

Несколько мыслей:

  • В plpgsql можно использовать несколько операторов RETURN, чтобы разные части вашего кода возвращали что-то другое, не выходя из функции. Но если вы предпочитаете иметь промежуточную таблицу для сбора информации и возвращать ее только один раз в конце, убедитесь, что таблица либо удалена вручную после завершения функции (или если она вызывает ошибку!), либо просто создайте ее как ON COMMIT DROP. Если вы предпочитаете первое, взгляните на UNLOGGED TABLES.
  • Рассмотрите возможность использования текста поверх character varying.
  • Ваш цикл WHILE использует возрастающее значение 1, пока не достигнет определенного предела. Вы можете использовать цикл FOR и избавиться от переменной i в предложении DECLARE. В этом нет ничего страшного, но в зависимости от размера вашей функции это может сделать вещи чище.
  • Вы можете использовать порядок параметра вместо его имени, например. $1. Это также не имеет большого значения, но позволяет избежать конфликтов и/или путаницы со столбцами, которые могут иметь одно и то же имя.