I was trying to call the function I created to fetch some data for particular time slot. Given below is a script of my function:
CREATE OR REPLACE FUNCTION my_function(
starttime timestamp with time zone,
endtime timestamp with time zone)
RETURNS TABLE("Deviceid" integer, "AlertTime" timestamp with time zone)
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
r record;
BEGIN
SELECT "DeviceID" , "AlertTime" FROM my_table
WHERE "AlertTime" BETWEEN starttime AND endtime;
END;
$function$;
ALTER FUNCTION public.my_function(timestamp with time zone, timestamp with time zone)
OWNER TO postgres;
When I am calling function with time '2016-12-15 00:00:01' to '2016-12-15 18:00:00' I am not getting any record. Even many records available for the time slot, I checked it by passing same time values for the query inside the function, its fetching data properly.
select * from my_function('2016-12-14 00:00:01','2016-12-15 18:00:00')
But when I am calling function with 2016-12-15 00:00:00' to '2016-12-15 18:00:00' I am able to get all records.
select * from my_function('2016-12-14 00:00:00','2016-12-15 18:00:00')
Even I tried to change the input parameters to "character varying" and convert the input internally to time stamp even then it is not working.
The explanation is obvious, isn't it?
All the matching rows from mytable have "AlertTime" greater or equal than 2016-12-14 00:00:00 and less than 2016-12-14 00:00:01.
Related
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')
I have written the same function in PL/PgSQL and PL/Python:
create function pythontest2()
returns TABLE(id bigint, timestamp_ timestamp without time zone, acknowledgedtimestamp timestamp without time zone, inactivetimestamp timestamp without time zone)
language plpython3u
as
$$
tablename = "dimension_alarms"
columns = ["id", "timestamp as TimeStamp_", "acknowledgedtimestamp", "inactivetimestamp"]
query_string = "select {0} from {1}".format(", ".join(columns), tablename)
return plpy.execute(query_string)
$$;
create function pythontest3() returns text
language plpython3u
as
$$
tablename = "dimension_alarms"
columns = ["id", "timestamp as TimeStamp_", "acknowledgedtimestamp", "inactivetimestamp"]
return "select {0} from {1}".format(", ".join(columns), tablename)
$$;
create function pythontest3execute()
returns TABLE(id bigint, timestamp_ timestamp without time zone, acknowledgedtimestamp timestamp without time zone, inactivetimestamp timestamp without time zone)
language plpgsql
as
$$
BEGIN
RETURN QUERY EXECUTE pythonTest3();
RETURN;
END
$$;
When I call select pythontest3execute(); and select pythonTest2();, the first statement executes in half the time of the second.
The first function calls "Execute" from a PL/PqSQL function, the second function calls plpy.execute(...). Both functions use the python interpreter to execute, so why is plpy.execute() in particular so slow?
Edit:
The average time it took to execute pythonTest2() was around 200ms, and the average time it took pythonTest3Execute() was about 80ms. The query returns around 150,000 results
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;
I need measure timelaps for testing the duration of function...
1) at the begin of function I assign value of now() to a variable called v_start;
2) before end the function I assign value of now() to a variable called v_end;
the problem is: the value of now() don't change during execution of function
Example
...
begin
v_start := now(); ex. "2018-02-14 10:03:52.394263+01"
...
...
v_end := now(); -- this value is equal to v_start
select EXTRACT(EPOCH FROM now()-now())/3600 into v_timelaps;
-- v_timelaps is always 0;
end;
Any solutions??? Thanx!
It is not supposed to. Because function runs in transaction and transaction start time does not change while function runs.
https://www.postgresql.org/docs/current/static/functions-datetime.html
clock_timestamp() timestamp with time zone Current date and time
(changes during statement execution);
or
statement_timestamp() timestamp with time zone Current date and
time (start of current statement);
not the
now() timestamp with time zone Current date and time (start of
current transaction);
formatting mine.
also check the https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
postgresql has date_trunc that can truncate the time stamp value to a specific unit, like hour or minute. I want to know if there's any build-in function that would allow me to truncate to 10 minutes?
I know one trick is to convert the time stamp to epoch, do some math, then convert back. But I don't like it.
There is no function you want, but as said in postgresql wiki you can define function for youself:
CREATE OR REPLACE FUNCTION round_time_10m(TIMESTAMP WITH TIME ZONE)
RETURNS TIMESTAMP WITH TIME ZONE AS $$
SELECT date_trunc('hour', $1) + INTERVAL '10 min' * ROUND(date_part('minute', $1) / 10.0)
$$ LANGUAGE SQL;
Generally rounding up to $2 minutes:
CREATE OR REPLACE FUNCTION round_time_nm(TIMESTAMP WITH TIME ZONE, INTEGER)
RETURNS TIMESTAMP WITH TIME ZONE AS $$
SELECT date_trunc('hour', $1) + ($2 || ' min')::INTERVAL * ROUND(date_part('minute', $1) / $2)
$$ LANGUAGE SQL;
here's an improved version of date_trunc
create cast (bigint as timestamptz) WITHOUT FUNCTION;
create cast (timestamptz as bigint) WITHOUT FUNCTION;
CREATE OR REPLACE FUNCTION date_trunc_by_interval( interval, timestamptz )
RETURNS timestamptz
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
AS $$
select
case when $2::bigint >= 0::bigint then
$2::bigint - $2::bigint % (extract (epoch from $1)*1000000 ) ::bigint
else
$2::bigint - $2::bigint % (extract (epoch from $1)*1000000 ) ::bigint
- (extract (epoch from $1)*1000000 ) ::bigint
end ::timestamptz
$$;
this allows rounding to any fixed-length interval eg: '864 seconds' (divinding days into 100 parts) or '14 days' dividing the calendar into fortnights. the basis is '2000-01-01 00:00:00.0 +00' which is the epoch used to compute postgres
timestamp values.
it works by coercing the timestamptz value and the interval into bigints and doing integer arithmetic on them then coercing them back to timestamps
negative inputs need special handling (the case statement) as % causes rounding towards zero.
Postgres 14 date_bin.
Example use
SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP '2001-01-01');
Result: 2020-02-11 15:30:00
The timescaleDb extension has a time_bucket function that supports day, minutes and lower intervals.
Note: it does currently not support months, years: see #414