Sidhu177
Sidhu177

Reputation: 11

How do I store date Variable in Postgres function?

So I am working to create a function that will delete the 1 month worth records from a table. The table is in postgres. As postgres does not have stored procedures I am trying to declare a function with the logic that will insert the 1 month records into a history table and then delete the records from the live table. I have the following code :

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';

So the above code compiles fine but when I try to run it by invoking it :- DeleteAndInsertTransaction(27) it gives me an Error: relation "savetime" does not exist and I have no clue what is going on here. If I take out the SELECT now() into saveTime; out of the function bloc and declare it before invoking the function then it runs fine but I need to store the current date into a variable and use that as a constant for the insert and delete and this is going against a huge table and there could be significant time difference between the insert and deletes. Any pointers as to what is going on here ?

Upvotes: 1

Views: 10236

Answers (1)

user330315
user330315

Reputation:

select .. into .. is the deprecated syntax for create table ... as select ... which creates a new table.

So, SELECT now() into saveTime; actually creates a new table (named savetime), and is equivalent to: create table savetime as select now(); - it's not storing something in a variable.

To store a value in a variable, you need to first declare the variable, then you can assign the value. But you can only do that in PL/pgSQL, not SQL

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

To insert into an existing table you need

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

To select the rows from the last x month, there is no need to store the current date and time in a variable to begin with. It's also easier to use make_interval() to generate an interval based on a specified unit.

You can simply use

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

And as you don't need a variable, you can actually do all that with a language sql function.

So the function would look something like this:

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;

Note that the language name is an identifier and should not be quoted.


You can actually do the DELETE and INSERT in a single statement:

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;

Upvotes: 2

Related Questions