Обсуждение: Calculation error
Hi:
I am new to postgresql (more familiar with Oracle) and am facing an issue I don't understand.
What I am trying to do is the following:
Given a start date/time and a stop date/time I want to calculate
the difference in seconds, using a calc_duration function.
When running this function using another function, run_calc it should
update the duration field in my int_performance_facts table,
But I get error:
WARNING: Error occurred while executing PL/pgSQL function calc_duration
WARNING: line 23 at assignment
ERROR: parser: parse error at or near "$1" at character 20
What am I doing wrong here ?
PS: I am running version 7.3.2 in a SUN/UNIX environment
Thanks in advance: Wil
Details:
========
my table definition (part of it) is:
------------------------------------
Table "public.int_performance_facts"
Column | Type | Modifiers | Description
-----------------+------------------------+-----------+-------------
duration | integer | |
start_date | date | |
start_date_id | integer | |
start_time | time without time zone | |
start_time_id | integer | |
stop_date | date | |
stop_date_id | integer | |
stop_time | time without time zone | |
stop_time_id | integer | |
My calculate function is:
----------------------------
CREATE OR REPLACE FUNCTION calc_duration (date,time,date,time) RETURNS integer AS '
DECLARE
p_start_date ALIAS FOR $1;
p_start_time ALIAS FOR $2;
p_stop_date ALIAS FOR $3;
p_stop_time ALIAS FOR $4;
v_startmoment timestamp;
v_stopmoment timestamp;
v_epoch_start integer;
v_epoch_stop integer;
v_duration integer := 0;
BEGIN
v_startmoment := timestamp(p_start_date,p_start_time);
v_epoch_start := date_part(epoch, v_startmoment);
v_stopmoment := timestamp(p_stop_date,p_stop_time);
v_epoch_start := date_part(epoch, v_stopmoment );
v_duration := v_epoch_stop - v_epoch_start;
RETURN v_duration;
END;
' LANGUAGE 'plpgsql' ;
I am calling this function from:
---------------------------------
CREATE OR REPLACE FUNCTION run_calc () RETURNS integer AS '
DECLARE
dummy integer ;
v_query varchar(2000);
BEGIN
v_query := ''update int_performance_facts
set duration = calc_duration
( start_date
, start_time
, stop_date
, stop_time
);
'';
execute v_query;
RETURN dummy;
END;
Wil Duis <Wil.Duis@asml.com> writes:
> v_startmoment := timestamp(p_start_date,p_start_time);
> v_epoch_start := date_part(epoch, v_startmoment);
> v_stopmoment := timestamp(p_stop_date,p_stop_time);
> v_epoch_start := date_part(epoch, v_stopmoment );
The function name "timestamp" needs to be double quoted here to avoid a
syntax conflict with the type declaration syntax TIMESTAMP(n). But
actually I'd use timestamptz, assuming that your dates and times are in
local time --- the above calculation will give the wrong answers across
a daylight-savings transition.
BTW I think you meant to assign to v_epoch_stop in the last line quoted.
You should also consider making v_epoch_start and v_epoch_stop be float8
not integer, if you want the code to not break in 2038.
> v_query := ''update int_performance_facts
> set duration = calc_duration
> ( start_date
> , start_time
> , stop_date
> , stop_time
> );
> '';
> execute v_query;
Seems like the hard way. Why not just do the UPDATE directly?
regards, tom lane
Wil Duis <Wil.Duis@asml.com> writes:
> Hi:
> I am new to postgresql (more familiar with Oracle) and am facing an issue I don't understand.
> What I am trying to do is the following:
It seems I've have a similar problem to you.
> ERROR: parser: parse error at or near "$1" at character 20
I kept getting this same error, heres what I was trying to do.
it := select int4(extract(epoch from timestamp $1 -
extract(epoch from timestamp $2));
This doesn't work for me, I get the same error message as you.
I'm very new to functions, I don't understand whats going
on, but I did manage to get it working using quote_literal,
but its very ugly.
create or replace function
subts(timestamp,timestamp)
returns int as
'
declare
it int;
ts1 alias for $1;
ts2 alias for $2;
qquery text;
rec record;
begin
qquery := ''select int4(extract(epoch from timestamp ''
|| quote_literal(ts1)
|| '' ) - extract(epoch from timestamp ''
|| quote_literal(ts2)
|| '' ))'';
FOR rec IN EXECUTE qquery LOOP
it := rec.int4;
END LOOP;
return it;
end
'
language 'plpgsql' IMMUTABLE;
The loop is ugly, but I couldn't work out any other way to do it.
Tom Lane <tgl@sss.pgh.pa.us> writes: > chestie <mcit@argus.net.au> writes: >> I kept getting this same error, heres what I was trying to do. > >> it := select int4(extract(epoch from timestamp $1 - >> extract(epoch from timestamp $2)); > > You should just write > > it := select int4(extract(epoch from $1) - > extract(epoch from $2)); It works (without the select, my fault). > You are confusing the syntax I'm just confused in general. :) Thanks for the explanation.
chestie <mcit@argus.net.au> writes:
> I kept getting this same error, heres what I was trying to do.
> it := select int4(extract(epoch from timestamp $1 -
> extract(epoch from timestamp $2));
You should just write
it := select int4(extract(epoch from $1) -
extract(epoch from $2));
You are confusing the syntax
timestamp 'string literal'
(or more generally, any type name followed by a string literal) with
something that you should apply to a non-constant value. That syntax
works *only* for literal constants.
In your example, $1 and $2 are already of type timestamp and require
no further conversion, so the extract()s will work fine as I show above.
If you did need a run-time type conversion, you'd have to write
"CAST($1 AS timestamp)" (the SQL-spec-approved syntax) or
"$1::timestamp" (Postgres' traditional notation).
regards, tom lane
Hi Tom
Sorry for my delayed reaction, but I didn't have much time yesterday.
On a trial and error way I tried a lot of variations, but up to now without success;
The closest to succes (I guess) was by using the following syntax:
v_startmoment := ''timestamp(''||p_start_date||'', ''||p_start_time||'')'';
but this resulted in error:
ERROR: Bad timestamp external representation 'timestamp(2003-05-14, 01:20:40)'
This supprised me since executing from commandline:
select timestamp'2003-05-10 01:20:40';
works fine!
So, all suggestions are still welcome.
Regards: Wil
Tom Lane wrote:
>
> The function name "timestamp" needs to be double quoted here to avoid a
> syntax conflict with the type declaration syntax TIMESTAMP(n). But
> actually I'd use timestamptz, assuming that your dates and times are in
> local time --- the above calculation will give the wrong answers across
> a daylight-savings transition.
>