Postgresql current datetime for past year - sql

Is there a function on postgresql that will let me get the current datetime for the past year or x number of past years?
I know i can do this select now() - interval '1 year'; but in a function how can i put the number of years in a variable
x := '2 year'
Is it possible to do this select now() - interval x;
I tried but it give me error

If you want to use variable you can do this:
CREATE OR REPLACE FUNCTION func(input integer)
RETURNS TIMESTAMP WITHOUT TIME ZONE AS
$BODY$
declare
result TIMESTAMP WITHOUT TIME ZONE;
begin
select now() - (input || ' years')::interval into result;
return result;
end;
$BODY$
LANGUAGE plpgsql VOLATILE

For the date, you would use:
select current_date - interval '1 year'
For the date/time:
select now() - interval '1 year'

Related

Add one day to Now() and return as default value in SQL query

I am attempting to add a day to NOW() and return as the values for a column.
This works
SELECT NOW() as date
But this gives an error
SELECT DATE_ADD( NOW(), INTERVAL 1 DAY) as date
Is there a way to achieve this in a postgres query?
Thanks
I don't think there's a date_add() function in PostgreSQL:
ERROR: function date_add(timestamp with time zone, interval) does not
exist
LINE 1: select date_add(now(), interval '1 day');
^
HINT: No function matches the given name and argument types. You
might need to add explicit type casts.
but you can use a regular + operator to add an interval to timestamptz that's returned by now(). Demo:
select now() + '1 day'::interval;
You can define that function for convenience:
create function date_add(arg1 timestamptz, arg2 interval)
returns timestamptz language sql as $$
select arg1+arg2
$$;
select date_add(now(), interval '1 day') as date;
-- date
---------------------------------
-- 2022-11-29 12:28:12.393508+00
But I don't think it's really more convenient than the operator. You'd also have to overload it to make sure how it deals with different types - you can see in the demo how by default PostgreSQL will try to guess and cast automatically.

How do I join a string and an int in PostgreSQL?

I have a procedure with an int parameter.
CREATE OR REPLACE PROCEDURE update_retention_policy(id int, days int)
language plpgsql
AS
$$
BEGIN
PERFORM add_retention_policy(('schema_' + id + '.my_hypertable'), days * INTERVAL '1 day', true);
END
$$;
The syntax for the add_retention_policy function is add_retention_policy('hypertable', INTERVAL 'x days', true). I want to prefix the hypertable with the schema which is always 'schema_' and then followed by the id parameter, how do I do that?
You just need to rewrite the INTERVAL part in your function call as days * INTERVAL '1 day'.
Instead of concatenating strings, you multiply the '1 day' interval by the days param.
EDIT: for the id part, you can just use the || operator, which is the string concatenation operator in Postgres, instead of +. You shouldn't even need to explicitly cast id to character varying

how to replace date in postgres with a static number

I am writing a Postgres procedure and I want to replace only date part of date with some static no.
eg:-
varDate Date default '2018-05-21';
Say I want to make this date as '2018-05-08';
Can anyone tell how to achieve this.
Till now what i have tried is this
varDate := varDate - interval '1 day' * 21 + interval '1 day' * 8;
The above expression gives me proper results. But is there any shortcut to change only the date part of the date.
As far as I understand you want to change the day of the month to 8.
One way to do this is to "truncate" the date to the start of the month, then add 8 days:
vardate := date_trunc('month', vardate)::date + 8;
date_trunc returns a timestamp that's why the cast ::date is needed.
Another option is to "build" a date based on the existing date:
vardate := make_date(extract(year from vardate)::int, extract(month from vardate)::int, 8);
Another option is to add a number of days to the date so you land on the 8th day:
select vardate::date + (8 - extract(day from vardate) * interval '1 day'

Show the next half hour time point in Postgres function

I am trying to create a function that shows the next half hour time.
So when the current time is 13:40, I want it to show 14:00 and not 13:30.
What I have created, gets the job done but on the nearest half hour time, not the future nearest:
CREATE OR REPLACE FUNCTION round_timestamp(
ts timestamptz
,round_secs int
) RETURNS timestamptz AS $$
DECLARE
_mystamp timestamp;
_round_secs decimal;
BEGIN
_round_secs := round_secs::decimal;
_mystamp := timestamptz 'epoch'
+ ROUND((EXTRACT(EPOCH FROM ts))::int / _round_secs) * _round_secs
* INTERVAL '1 second';
RETURN _mystamp;
END; $$ LANGUAGE plpgsql IMMUTABLE;
Any ideas on how to make this work to display the future nearest half hour interval?
To avoid tripping over on using epoch and floating point arithmetics, you can rely on date arithmetics, with the additional benefit of making it clearer what is going on:
create or replace function round_tstz(ts timestamptz)
returns timestamptz
as $$
select date_trunc('hour', $1) +
-- what hour will it be in 30 min?
case date_trunc('hour', $1 + interval '30 min')
-- the same: round to next half hour
when date_trunc('hour', $1) then interval '30 min'
-- not the same: round to next hour
else interval '1 hour'
end;
$$ language sql stable;
# select now()::timestamptz(0);
now
------------------------
2014-12-05 14:34:30+01
(1 row)
# select round_tstz(now()), round_tstz(now() + interval '30 min');
round_tstz | round_tstz
------------------------+------------------------
2014-12-05 15:00:00+01 | 2014-12-05 15:30:00+01
(1 row)
Trivially, add 1 to the rounded down epoch before scaling it back up to a timestamp:
CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
RETURNS timestamptz AS $$
BEGIN
RETURN timestamptz 'epoch'
+ (ROUND((EXTRACT(EPOCH FROM ts))::int / round_secs) + 1) * round_secs
* INTERVAL '1 second';
END; $$ LANGUAGE plpgsql IMMUTABLE;
There is no need for the local variables.
You can use ceil() (or ceiling()) and floor() to round up and down, respectively.
If your function is that simple, you can write it in LANGUAGE SQL too, which makes it more simple/readable (and plannable too by the parser):
CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
RETURNS timestamptz
LANGUAGE SQL
IMMUTABLE
AS $func$
SELECT timestamptz 'epoch'
+ ceiling(EXTRACT(EPOCH FROM ts) / round_secs)
* round_secs
* INTERVAL '1 second'
$func$;
SQLFiddle
You need to add X minutes to the current amount of minutes M in the timestamp, where:
X = 30 - M % 30 - 30 * ((M % 30)=0)::int
You subtract the remainder of the division to 30 from 30, and then only if that remainder is 0, subtract another 30, so that :00 and :30 values are kept and not rounded up as well.
For example, if the time is 14:11, then M = 11, you need to add 19 minutes to reach 14:30 (30 - 11 % 30 = 19), for 14:47, M = 47, you need to add 13 minutes to reach 15:00 (30 - 47 % 30 = 13). The only exception to that rule is the case when the remainder is 0, i.e. hours such as 14:30, 15:00, etc. - and that's where the last term in the formula comes into play - subtracting the product of 30 * (0 or 1, depending on the remainder of the division to 30).
CREATE FUNCTION round_up(timestamptz) RETURNS timestamptz AS $$
SELECT
$1 + '1 minute'::interval * (
30 - (EXTRACT('minute' FROM $1)::int % 30)
- 30 * ((EXTRACT('minute' FROM $1)::int % 30)=0)::int
);
$$ LANGUAGE sql IMMUTABLE;

Checking timestamps in PL/pgSQL

If I have a function in PL/pgSQL that takes in a timestamp, what is the best way to identify whether that date is less than 12 months in the past?
e.g.
CREATE FUNCTION do_something(foo timestamp) ....
-- IF foo is less than 12 months in the past THEN
-- do something
-- END IF;
END;
Read about intervals on PostgreSQL doc: Date Types. Use something like:
where foo < CURRENT_TIMESTAMP - interval '12 months'
Or, equivalently: age(foo) < interval '12 months'