subtract now() with a date in pgsql trigger function - postgresql

I am stuck in subtracting now() with modified date in pgsql trigger function.
This is my query,
CREATE OR REPLACE FUNCTION trigger_cust_order_mst_after_update()
RETURNS trigger AS
$BODY$
declare
v_log_max_ldate timestamp;
v_time time;
BEGIN
v_log_max_ldate = (select max(d_Ldate ) from cust_order_log where n_ord_srno = new.n_srno);
v_time = now() - v_log_max_ldate;
when this trigger executes,an error occurs as,
ERROR: invalid input syntax for type date: "1"
CONTEXT:PL/PgSQL function trigger_cust_order_mst_after_update()
Please help me out from this.

Related

passing variable date with fixed time to a function

I am trying to create a function which accepts two arrays, and a date. The function uses the date
in a way where I want hardcoded values of time (with timezone) which are already stated in the function body (in the orig_dataset CTE). Here is my function so far:
CREATE or replace FUNCTION f_loop_in_lockstep_final(_id_arr int[], _counter_arr int[], d_date date)
RETURNS TABLE (uc_name_ varchar)
LANGUAGE plpgsql AS
$func$
DECLARE
_id int;
_counter int;
d_date date;
BEGIN
FOR _id, _counter IN
SELECT *
FROM unnest (_id_arr, _counter_arr) t
LOOP
RETURN QUERY
with orig_dataset as (
select routes
from campaign_routes cr
where cr.created_at between 'd_date 06:00:00 +05:00' and 'd_date 18:00:00 +05:00'
)
-- a couple of further CTE's result in a final CTE called final_cte
select * from final_cte;
END LOOP;
END
$func$;
When I use the following function call:
SELECT * FROM f_loop_in_lockstep_final('{454,454}'::int[]
, '{2,3}'::int[], to_date('2023-01-17','YYYY-MM-DD'));
I receive the following error:
SQL Error [22007]: ERROR: invalid input syntax for type timestamp with time zone: "d_date 06:00:00 +05:00"
Where: PL/pgSQL function f_loop_in_lockstep_final(integer[],integer[],date) line 14 at RETURN QUERY
Well, obviously 'd_date 06:00:00 +05:00' is not a valid date literal.
You need to add a time value to the variable to create a timestamp value based on that:
where cr.created_at between d_date + '06:00:00 +05:00'::time
and d_date + '18:00:00 +05:00'::time
I am not entirely sure that using a time zone offset in a time constant works correctly, so maybe you need:
where cr.created_at between ((d_date + '06:00:00'::time) at time zone '+05:00')
and ((d_date + '18:00:00'::time) at time zone '+05:00')

How to compare timestamp with integer in Postgres?

I want to have a trigger that would remove existing records where they have lived for more then 10 mins
drop table if exists authorization_code;
create table if not exists authorization_code(
id int generated always as identity,
created_at timestamptz not null
);
drop function if exists remove_expired();
create function remove_expired()
returns trigger
language plpgsql
as $$
begin
--NOTE 10 mins as recommended by the OAuth2 spec
delete from authorization_code where now() - created_at > 600;
return NEW;
end;
$$;
drop trigger if exists clean_up_expired_code on authorization_code;
create trigger clean_up_expired_code
before insert
on authorization_code
for each row
execute procedure remove_expired();
But right now if I insert, I would get an error like this:
sso=# insert into authorization_code(created_at) values(now());
ERROR: operator does not exist: interval > integer
LINE 1: ...lete from authorization_code where now() - created_at > 600
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
QUERY: delete from authorization_code where now() - created_at > 600
CONTEXT: PL/pgSQL function remove_expired() line 4 at SQL statement
What is the correct way to achieve what I want?
The result of subtracting two timestamps is an interval so you can directly compare that:
where now() - created_at > interval '10 minutes';
Or if you want to provide duration as e.g. a parameter indicating the number of seconds:
where now() - created_at > make_interval(secs => 600);
Try using this modified version of the remove_expired() function
halley=> \sf remove_expired
CREATE OR REPLACE FUNCTION public.remove_expired()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
--NOTE 10 mins as recommended by the OAuth2 spec
delete from authorization_code where EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)-EXTRACT(EPOCH FROM created_at) > 600;
return NEW;
end;
$function$

Pass date intervals as function parameters

I have a database function as below:
drop function test(month_interval text)
create or replace function test (month_interval text) returns date as
$$
select ('2020-07-01'::date - interval month_interval)::date;
$$ language sql;
select * from test('2 months')
I have a scenario where I want to dynamically compute month intervals and want to have one database query that can be used by passing month intervals as function parameters. However when i do this it gives me the following error :
ERROR: syntax error at or near "month_interval"
You could cast the text to an interval:
create or replace function test (month_interval text) returns date as
$$
select ('2020-07-01'::date - month_interval::interval)::date;
$$ language sql;
select test('2 months');
But why not pass an interval directly?
create or replace function test (month_interval interval) returns date as
$$
select ('2020-07-01'::date - month_interval)::date;
$$ language sql;
select test(interval '2 months');
Alternatively you can pass the number of months, then use make_interval:
create or replace function test (num_months int) returns date as
$$
select ('2020-07-01'::date - make_interval(months => num_months))::date;
$$ language sql;
select test(2);

How to extract miliseconds from timestamp dynamically in postgres plpgsql?

I want to get milliseconds from a 'Timestamp with timezone' using a plsql function.
I am able to generate the following function, but it is leading to truncation of miliseconds.
CREATE or REPLACE FUNCTION getMSFromTime(t1 timestamp with time zone)
RETURNS bigint AS $$
declare time1 double precision ;
BEGIN
SELECT EXTRACT(EPOCH FROM t1) into time1;
return time1;
END;
$$ LANGUAGE plpgsql;
but it ignores miliseconds
SELECT getMSFromTime('2019-02-11 08:01:33.423+00') //1549872093
SELECT getMSFromTime('2019-02-11 08:01:33.000+00') //1549872093
I am able to get a PostgreSQL way so that millisecond decimals are preserved as well, using:
SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2019-02-11 08:01:33.423+00'); // 1549872093.423
But I am not able to integrate it into a function and it gives following error:
syntax error at or near "t1"
LINE 5: ...ELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE t1) into t..
CREATE or REPLACE FUNCTION getMSFromTime2(t1 timestamp with time zone)
RETURNS bigint AS $$
declare time1 double precision ;
BEGIN
SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE t1) into time1;
return time1;
END;
$$ LANGUAGE plpgsql;
Please suggest a way so as to create a PostgreSQL function which can do this functionality.
extract() returns a double value that represents seconds, by casting that to a bigint you lose the fractional seconds (=milliseconds)
If you want a bigint representing milliseconds, you need to multiple the result with 1000.
There is also no reason to use PL/pgSQL for such a simple thing:
CREATE or REPLACE FUNCTION getmsfromtime(t1 timestamp with time zone)
RETURNS bigint
AS $$
SELECT (EXTRACT(EPOCH FROM t1)*1000)::bigint;
$$
LANGUAGE sql;

SQL state: 22P02 invalid input syntax for integer error in recursive PL/pgSQL function

I am new to PostgreSQL and I am currently in the process of writing a recursive function to find tram times.
I have defined a custom type as:
CREATE TYPE single_journey AS
(tram_id integer,
departure_station text,
departure_time time without time zone,
destination_station text,
arrival_time time without time zone);
and the function...
CREATE OR REPLACE FUNCTION find_tram_same_line(text, text, time) returns single_journey AS $$
DECLARE
departure_station ALIAS FOR $1;
destination_station ALIAS FOR $2;
query_time ALIAS FOR $3;
journey single_journey;
BEGIN
journey.departure_station := departure_station;
journey.destination_station := destination_station;
SELECT tram_id, time
INTO journey.tram_id, journey.departure_time
FROM station_departure_times
JOIN stations on station_departure_times.station_id = stations.station_id
WHERE stations.name = departure_station
AND time > query_time
ORDER BY time ASC
LIMIT 1;
SELECT time
INTO journey.arrival_time
FROM station_departure_times
JOIN stations on station_departure_times.station_id = stations.station_id
WHERE stations.name = destination_station
AND tram_id = journey.tram_id;
IF journey.arrival_time IS NULL THEN
SELECT find_tram_same_line(
departure_station,
destination_station,
(query_time + interval '1 minute'))
INTO journey;
END IF;
RETURN journey;
END;
$$ LANGUAGE plpgsql;
The query:
SELECT find_tram_same_line('GrimesDyke', 'CitySquare', '09:00:00');
Whenever I run the query, I get an error:
********** Error **********
ERROR: invalid input syntax for integer: "(24,GrimesDyke,09:07:00,CitySquare,10:19:00)"
SQL state: 22P02
Context: PL/pgSQL function find_tram_same_line(text,text,time without time zone) line 29 at SQL statement
I have spent some time trying to figure out why this is to no avail. The only integer in the single_journey type is the tram_id but I am unsure why this is causing an issue. Does anyone know why this might be?
Edit: Should be noted that (24,GrimesDyke,09:07:00,CitySquare,10:19:00) is what I was expecting.