Adding sum of current_timestamp and days column in Postgres - postgresql

I want update a column by adding days to current time. In pseudosyntax it would be:
UPDATE foo
SET time = current_timestamp + days::integer
days is a column in the same table.

select now() + cast('1 day' as interval) * 3 -- example: 3 days

create function add_days_to_timestamp(t timestamptz, d int)
returns timestamptz
as
$$
begin
return t + interval '1' day * d;
end;
$$ language 'plpgsql';
create operator + (leftarg = timestamptz, rightarg = int,
procedure = add_days_to_timestamp);
Now this would work:
update foo set time = current_timestamp + 3 /* day variable here,
or a column from your table */
Note:
for some reason, adding an integer to date is built-in in Postgres, this would work:
select current_timestamp::date + 3 -- but only a date
this would not(unless you define your own operator, see above):
select current_timestamp + 3

calculatedDate timestamp without time zone;
calculatedDate := current_timestamp + interval '1' day * days_count;

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;

How can i create n columns in postgresql?

I am trying to write a function that returns random start time (it must be between now and a week long) and an endtime. I wrote this function:
CREATE OR REPLACE FUNCTION random_start_end_time(n integer)
RETURNS TABLE (startime TIMESTAMP WITH TIME ZONE, endtime TIMESTAMP WITH TIME ZONE)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY
SELECT NOW() + (random() * (NOW()+'7 days' - NOW())) as startime;
SELECT NOW() + (random() * (NOW()+'7 days' - NOW())) as endtime;
END;
$BODY$
I can't find out how to generate multiple columns. For example I want n=100 columns of random start time and end time to be generated.
In general I can't understand how I can fill an empty table (with this function I am going to fill a table later).
Any thoughts would be valuable.
Thank you.
Use RETURN NEXT to add a row to the result set of a table function and RETURN to end the function execution. You also have to decide if you want a function that returns two columns or two rows. Your case looks like you want to do something like:
CREATE OR REPLACE FUNCTION random_start_end_time(
OUT starttime TIMESTAMP WITH TIME ZONE,
OUT endtime TIMESTAMP WITH TIME ZONE
) RETURNS record
LANGUAGE sql AS
$BODY$
WITH start AS (
SELECT current_timestamp + random() * INTERVAL '7 days' as starttime
)
SELECT starttime,
starttime + random() * INTERVAL '7 days' as endtime
FROM start;
$BODY$;
Call it like
SELECT * FROM random_start_end_time();
If you really want to return several rows, that would be
CREATE OR REPLACE FUNCTION random_start_end_time()
RETURNS SETOF timestamp with time zone
LANGUAGE plpgsql AS
$BODY$
BEGIN
RETURN NEXT current_timestamp + random() * INTERVAL '7 days';
RETURN NEXT current_timestamp + random() * INTERVAL '7 days';
RETURN; /* end the function */
END;
$BODY$;

how to get the next date for a day of month

thanks for reading, this is the situation
I have a current_date and a day of month, so i need to know what will be the next date for this day of month, having in mind that some month don't have 30 and 31.
Example:
current_date = '2018-09-24'
day_of_week = 31
Expected result: '2018-12-31'
Currently i have this:
create or replace function next_diff(vals int[], current_val int) returns int as
$$
declare v int;
declare o int := vals[1];
begin
foreach v in array vals loop
if current_val >= o and current_val < v then
return v - current_val;
end if;
o := v;
end loop;
return vals[1] - current_val;
end;
$$ language plpgsql;
and this:
create or replace function next_day_of_month(days_of_month int[], curr_date date) returns date as
$$
declare cur_dom int := extract(day from curr_date);
declare next_diff int := next_diff(days_of_month, cur_dom);
begin
if next_diff < 0 then
curr_date := curr_date + '1 months'::interval;
end if;
curr_date := curr_date + (next_diff || 'days')::interval;
return curr_date;
end;
$$ language plpgsql;
but for this calling:
select next_day_of_month(array[31], '2018-09-24');
i am getting:
"2018-10-01"
Extra example
If i have this value
current_date = '2018-02-01'
day_of_week = 31
i will need the next month with 31th but i can't get '2018-02-31' because February don't have 31th then i should get '2018-02-31' because March have 31th.
Conclusion
if the month don't have the specified day must ignore the month and jump to the next.
thanks for all
Final method
Using Carlos Gomez answer, i create this PostgreSQL function and work perfectly:
create or replace function next_day_date(curr_date date, day_of_month int) returns date as
$$
declare next_day date;
begin
SELECT next_day_date into next_day FROM (
SELECT make_date_nullable(EXTRACT(year from n.month)::int, EXTRACT(month from n.month)::int, day_of_month) AS next_day_date
FROM (
SELECT generate_series(curr_date, curr_date + '3 months'::interval, '1 month'::interval) as month
) n
) results
WHERE results.next_day_date IS NOT NULL and results.next_day_date > curr_date LIMIT 1;
return next_day;
end;
$$ language plpgsql;
just add other filter in where clause and results.next_day_date > curr_date to prevent get the same or previous values for specified date
Thanks everyone for helping
Thenks Carlos you are the best
Gracias carlos eres el mejor :)
Your examples don't really match up but I think I know what you are trying to solve for (your first example result should be '2018-10-31' since October has 31 days and your second example result should be '2018-03-31'). It seems that given a date and a day of month you want to find the next month that has that day of month. To do this, I would do the following:
This function just wraps make_date to let it return null since it throws an exception if a date given to it is out of bounds (like February 30).
CREATE OR REPLACE FUNCTION make_date_nullable(year int, month int, day int)
RETURNS date as $$
BEGIN
RETURN make_date(year, month, day);
EXCEPTION WHEN others THEN RETURN null;
END;
$$ language plpgsql;
This SELECT first generates the next three months starting with the current one, then makes date out of them with your provided day_of_month and finally gets the first one that isn't null (exists according to postgresql.
SELECT next_day_date FROM (
SELECT make_date_nullable(EXTRACT(year from n.month)::int, EXTRACT(month from n.month)::int, day_of_month) AS next_day_date
FROM (
SELECT generate_series(current_date, current_date + '3 months'::interval, '1 month'::interval) as month
) n
) results
WHERE results.next_day_date IS NOT NULL LIMIT 1;
Hope this helps!

Add minutes to CURRENT_TIMESTAMP in PostgreSQL

I have a procedure in PostgreSQL that I want to add the number of minutes to CURRENT_TIMESTAMP like below
timestamp_var := CURRENT_TIMESTAMP + interval '20 minutes';
But the number of minutes is a parameter.
Do we have the functions to do this?
Pls help me in this case
CREATE OR REPLACE FUNCTION modify_time(id users.id%TYPE, min integer) AS $$
BEGIN
UPDATE
users
SET
modified_at = CURRENT_TIMESTAMP
WHERE
user_id = id;
END
$$ LANGUAGE plpgsql;
I want to add min minutes to CURRENT_TIMESTAMP
thanks
You can multiply intervals by integers. The following gives you a timestamp 20 minutes in the future:
select current_timestamp + (20 * interval '1 minute')
Or, as murison mentions in another answer to this question, there is a more succinct way to express this:
select current_timestamp + (20 ||' minutes')::interval
So, your code could look like:
CREATE OR REPLACE FUNCTION modify_time(id users.id%TYPE, min integer) AS $$
BEGIN
UPDATE
users
SET
modified_at = CURRENT_TIMESTAMP + (min * interval '1 minute')
WHERE
user_id = id;
END
$$ LANGUAGE plpgsql;
the other way is
select current_timestamp + (20 ||' minutes')::interval
If You need half minute or secounds :
SELECT current_timestamp + (50 * interval '1 seconds');