PostgreSQL - using variable inside quotes - postgresql

I am trying to use a variable for an expression like this
NOW() - INTERVAL '5 days'
But getting errors:
CREATE OR REPLACE FUNCTION some.archive() RETURNS VOID AS
$$
DECLARE
p_archive_depth CONSTANT VARCHAR := '5 days';
BEGIN
IF (date(p_table_date) < date(NOW() - INTERVAL p_archive_depth))
THEN
RAISE INFO '%', p_table_name;
END IF;
END;
$$ LANGUAGE plpgsql;
Also tried without success:
'' || p_archive_depth || ''
'' p_archive_depth ''

You need to define the variable with the data type interval
DECLARE
p_archive_depth CONSTANT interval := interval '5 days';
BEGIN
IF date(p_table_date) < (now() - p_archive_depth)::date

a_horse_with_no_name's answer is, of course, correct, but I'd like to offer an alternative to round it out in case you're getting the string value dynamically (e.g., querying it, getting it as an argument from the user, etc). You could take the string value of '5 DAYS' and explicitly cast it to an interval using the :: operator:
IF (date(p_table_date) < date(NOW() - p_archive_depth::INTERVAL))
-- Here -----------------------------------------^

Related

postgres interval add variable current_setting not work

set session myconstants.test = '10';
set session myconstants.testb = '10 min';
SELECT now()::time - interval concat (current_setting('myconstants.selfName')::varchar,' min');
SELECT now()::time - INTERVAL '10 min';
set session myconstants.test = '10';
SELECT now()::time - interval current_setting('myconstants.testb')::varchar;
SELECT now()::time - INTERVAL '10 min';
i want add variable in interval function,but current_setting not work..how could i solve it?i use postgres
You need to cast the variable value to an interval:
SELECT now()::time - current_setting('myconstants.testb')::interval
The prefix notation interval '....' only works with constants following it.
You can also try make_interval.
SET session myconstants.test = 10;
SELECT
now() + make_interval(mins => current_setting('myconstants.test')::int);
i found this solution,operator does not exist: timestamp with time zone + integer in PostgreSql.
create function addit(timestamptz,int) returns timestamptz immutable language sql as $$
select $1+ interval '1 hour'*$2
$$;
create operator + (leftarg =timestamptz, rightarg =int, procedure=addit);
create function minusit(timestamptz,int) returns timestamptz immutable language sql as $$
select $1+ interval '-1 hour'*$2
$$;
create operator - (leftarg =timestamptz, rightarg =int, procedure=minusit);
create + and - operator ,and execute
set session myconstants.testb = -1;
select start_time ,start_time - current_setting('myconstants.testb')::integer from besoccer_team bt ;
select start_time ,start_time - current_setting('myconstants.testb')::integer from besoccer_team bt ;
start_time is timestamp type
set session myconstants.testb = -1;
select now()::timestamp , now()::timestamp - current_setting('myconstants.testb')::integer from besoccer_team bt ;
select now()::timestamp , now()::timestamp - current_setting('myconstants.testb')::integer from besoccer_team bt ;

PostgreSQL - Reference a variable value in select statement interval

I'm trying to calculate a value in a variable then use that value to drive a interval statement further on.
Running on PG 9.6.
We can get to PG 13 if there is something added since then we can use.
Example:
CREATE OR REPLACE FUNCTION public.demofunc(
int,
int,
date)
returns date
LANGUAGE plpgsql AS $$
DECLARE
diffvalue text;
returndate date;
BEGIN
diffvalue:= ($2 - $1);
returndate := (SELECT $3 - INTERVAL 'diffvalue days');
return returndate;
END$$;
This is a simplified version of what I want to achieve, the interval of the numbers of days to remove is based on a calculation that's done in the function. So its not a simple A - B but the end result is
I can't seem to get the function to resolve the "diffvalue" before running the select statement. I've tried using int and text and varchar and concat the string for anything.
Sorry for anything obvious i might be missing, only started this today.
If your diffvalue is in reality an integer, you can use the make_interval function to create an interval based on that number:
returndate := $3 + make_interval(days => diffvalue);
If diffvalue is a decimal that can represent fractional days, make_interval can't be used.
In that case you can multiply an interval of 1 day with that value:
returndate := $3 + interval '1 day' * diffvalue;

postgres procedure giving ERROR: invalid input syntax for type timestamp: "select CURRENT_TIMESTAMP - INTERVAL '7 day'"

I have created postgres procedure, I am not writing whole procedure here, Just writing the part which is giving error as belows,
create or replace procedure xyz() as $$
declare
v_time timestamp without time zone;
v_retain_days int;
Begin
select retain_days from abc into v_retain_days;
v_time := cast('select CURRENT_TIMESTAMP - INTERVAL ''' || v_retain_days || ' day''' as timestamp) ;
END;
With this procedure call, Its giving error as below:
ERROR: invalid input syntax for type timestamp: "select CURRENT_TIMESTAMP - INTERVAL '7 day'"
Can anyone help in this?
No need for a SELECT, dynamic SQL, casting or string concatenation:
v_time := CURRENT_TIMESTAMP - INTERVAL '1 day' * v_retain_days;
or alternatively:
v_time := CURRENT_TIMESTAMP - make_interval(days => v_retain_days);

What is the difference between INTERVAL '0 days' and '0 days'::INTERVAL in postgres

I am trying to create a basic table with a list of dates in psql using a loop. The code is shown below
DO $$
DECLARE counter INTEGER :=0;
date_interval VARCHAR(250) :='0 DAYS';
BEGIN
DROP TABLE IF EXISTS temp_dates;
CREATE TABLE temp_dates (
date DATE
);
WHILE counter < 12 LOOP
date_interval := counter || ' DAYS';
INSERT INTO temp_dates
--SELECT DATE_TRUNC('DAYS', CURRENT_DATE) - date_interval :: INTERVAL;
SELECT (DATE_TRUNC('DAYS', CURRENT_DATE)) - (INTERVAL date_interval);
counter := counter + 1;
END LOOP;
END $$;
In the above query
SELECT DATE_TRUNC('DAYS', CURRENT_DATE) - date_interval :: INTERVAL;
works. But the following does not work
SELECT (DATE_TRUNC('DAYS', CURRENT_DATE)) - (INTERVAL date_interval);
Basically the only difference date_interval :: INTERVAL vs INTERVAL date_interval
But it works when I directly do something like INTERVAL '2 days' but it fails when I use a variable.
So my question is two fold
What is the difference between INTERVAL '2 days' and '2 days'::INTERVAL. From what I understand both are typecasting.
Why does INTERVAL '2 days' work but it fails when using a variable
I am sure I am missing something fairly obvious when it comes to escaping quotation marks but I am not sure. Any help would be greatly appreciated.
As the documentation states clearly, the syntax
INTERVAL '0 days'
is for constants, that is, the string has to be a literal.
It is not a syntax for type casts like '0 days'::interval, which allow you to change the type of an arbitrary expression.

PostgreSQL: month := interval '30 days';

Trying to delete records older than 1 month from 2 tables, where 1 references the "id" column in another:
create or replace function quincytrack_clean()
returns void as $BODY$
begin
month := interval '30 days';
delete from hide_id
where id in
(select id from quincytrack
where age(QDATETIME) > month);
delete from quincytrack
where age(QDATETIME) > month;
end;
$BODY$ language plpgsql;
but this fails with:
ERROR: syntax error at or near "month"
LINE 1: month := interval '30 days'
^
QUERY: month := interval '30 days'
CONTEXT: SQL statement in PL/PgSQL function "quincytrack_clean" near line 2
I'm reading the doc, but don't understand what's wrong with my declaration...
You need to declare the variable 'month', viz.:
declare
month interval;
begin
month := interval '30 days';
end;
Also, you might want to re-examine your "where" criteria. If QDATETIME is an indexed column, I don't think it will use the index, whereas QDATETIME < (now() - month) would.
You need to declare the variable before you can use it.
...
DECLARE
month INTERVAL;
BEGIN
month := interval '30 days';
...
But I would avoid using variable names that are reserved words or internal function names.