Как сохранить переменную даты в функции Postgres? - PullRequest
1 голос
/ 21 февраля 2020

Итак, я работаю над созданием функции, которая будет удалять записи за 1 месяц из таблицы. Таблица в postgres. Поскольку postgres не имеет хранимых процедур, я пытаюсь объявить функцию с логикой c, которая вставит записи за 1 месяц в таблицу истории и затем удалит записи из действующей таблицы. У меня есть следующий код:

CREATE FUNCTION DeleteAndInsertTransaction(Integer)
    RETURNS Void
AS $Body$

SELECT now() into saveTime;

SELECT * INTO public.hist_table  
FROM (select * from public.live_table
    WHERE update < ((SELECT * FROM saveTime) - ($1::text || ' months')::interval)) as sub;

delete from public.live_table
where update < ((SELECT * FROM saveTime) - ($1::text || ' months')::interval);

DROP TABLE saveTime;     

$Body$
Language 'sql';

Таким образом, приведенный выше код компилируется нормально, но когда я пытаюсь запустить его, вызывая его: - DeleteAndInsertTransaction(27), он дает мне Error: relation "savetime" does not exist, и я понятия не имею, что здесь происходит Если я извлекаю SELECT now() into saveTime; из функции blo c и объявляю ее перед вызовом функции, то она работает нормально, но мне нужно сохранить текущую дату в переменной и использовать ее в качестве константы для вставки, удаления и это идет против огромной таблицы, и между вставкой и удалением может быть значительная разница во времени. Есть какие-нибудь указатели относительно того, что здесь происходит?

1 Ответ

2 голосов
/ 21 февраля 2020

select .. into .. является устаревшим синтаксисом для create table ... as select ..., который создает a новую таблицу.

Таким образом, SELECT now() into saveTime; фактически создает новую таблицу (с именем savetime) и эквивалентно: create table savetime as select now(); - что-то не хранится в переменной.

Чтобы сохранить значение в переменной, необходимо сначала объявить переменная, тогда вы можете присвоить значение. Но это можно сделать только в PL / pg SQL, а не SQL

CREATE FUNCTION DeleteAndInsertTransaction(p_num_months integer)
  returns void
as
$Body$
declare
  l_now timestamp;
begin
  l_now := now();
  ...
end;
$body$
language plpgsql;

. Чтобы вставить в существующую таблицу, вам нужно

insert into public.hist_table  
select * 
from public.live_table.

. Чтобы выбрать строки из в прошлом месяце нет необходимости сохранять текущую дату и время в переменной для начала. Также проще использовать make_interval() для генерации интервала на основе указанной единицы измерения.

Вы можете просто использовать

select *
from live_table
where updated_at <= current_date - make_interval(mons => p_pum_months);

И поскольку вам не нужна переменная, вы можете на самом деле сделать все это с помощью функции language sql.

Таким образом, функция будет выглядеть примерно так:

CREATE FUNCTION DeleteAndInsertTransaction(p_num_months integer)
    RETURNS Void
AS 
$Body$

  insert into public.hist_table  
  select *
  from live_table
  where updated_at < current_date - make_interval(months => p_pum_months);

  delete from public.live_table
  where updated_at < current_date - make_interval(months => p_pum_months);

$Body$
Language sql;

Обратите внимание, что имя языка является идентификатором и не должно заключаться в кавычки.


Вы можете на самом деле выполнить DELETE и INSERT в одном выражении:

with deleted as (
  delete from public.live_table
  where updated_at <= current_date - make_interval(months => p_pum_months)
  returning * 
)
insert into hist_table
select *
from deleted;
...