Разбор возвращаемого типа записи на несколько столбцов в PostgreSQL

#sql #postgresql

#sql #postgresql

Вопрос:

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

 SELECT bank_id, myfunction(document_id,'DF') FROM timeline_chronicle WHERE document_id = 102;
  

Приведенное выше утверждение возвращает следующее:

 --------------------------------------
bank_id   |   record
----------------------------------------
9006      | (DOCUMENT_IS_ACCEPTED,"2020-07-03 16:37:28","2020-07-03 16:41:58",270)
----------------------------------------------------------------------------------
  

Но мне нужна версия ниже

 --------------------------------------
bank_id   |   event_type         | start_time          | end_time            | difference   |
-----------------------------------------------------------------------
9006      | DOCUMENT_IS_ACCEPTED | 2020-07-03 16:37:28 | 2020-07-03 16:41:58 |  270
----------------------------------------
  

Кроме того, я попробовал нижеприведенную версию, но в любом случае не работает:

 SELECT bank_id, myfunction(document_id,'DF') as (event_type text,start_time TIMESTAMP,end_time TIMESTAMP,difference integer) FROM timeline_chronicle WHERE document_id = 102;
  

Версия Postgre: 9.6.18. Моя функция Postgre приведена ниже:

 CREATE OR REPLACE FUNCTION myfunction(doc_id integer,oper_name2 text) 
RETURNS RECORD AS $$
DECLARE

start_tim               timestamp(0) without time zone;
end_tim                 timestamp(0) without time zone;
event_typo              text;
tim_diff                integer;
ret                     RECORD;

BEGIN
    start_tim := (SELECT to_timestamp(MIN(created_at))::timestamp FROM table WHERE document_id = 62);
    SELECT event_type,created_at INTO event_typo,end_tim FROM (
        SELECT document_id,oper_name,event_type,to_timestamp(created_at)::timestamp as created_at, 
            case when event_type in ('DOCUMENT_IS_DENY','DOCUMENT_IS_ACCEPTED')  then 2 else 1 end as status
        FROM table  
        WHERE document_id = 62 order by created_at asc
        ) s WHERE status = 2 order by created_at asc limit 1;

    tim_diff:= (select extract(epoch from (end_tim-start_tim)));  
    SELECT event_typo,start_tim,end_tim,tim_diff INTO ret;
    RETURN ret;
   
END;
$$ LANGUAGE plpgsql;
  

Комментарии:

1. Какой тип данных created_at? Почему это не временная метка?

2. В таблице это integer тип

3. Приведение ::timestamp бесполезно, поскольку to_timestamp() уже возвращает временную метку.

Ответ №1:

Вам нужна типизированная запись, чтобы видеть имена столбцов. Для этого вам необходимо создать правильный возвращаемый тип:

 create type function_result as 
( 
  event_type text,
  start_time TIMESTAMP,
  end_time TIMESTAMP,
  difference bigint
);
  

Затем в вашей функции используйте:

 return (event_typo,start_tim,end_tim,tim_diff)::function_resu<
  

( ret переменная не нужна)

Затем вы можете развернуть запись в запросе на столбцы, используя:

 SELECT bank_id, (myfunction(document_id,'DF')).* 
FROM timeline_chronicle 
WHERE document_id = 102;
  

Обратите внимание, что:

 tim_diff := (select extract(epoch from (end_tim-start_tim))); 
  

может быть упрощен до:

 tim_diff := extract(epoch from (end_tim-start_tim));