Обсуждение: plpgsql function returning SETOF
Hello all novices and experts,
I didn't understand how to create a function, which returns a varying
number of records. Worse, it seems, that I didn't understand the SETOF
feature at all... Two examples:
1.)
should give two records in the year 1990: 1990.06.17 and 1990.10.03,
all other years have minimum 1 NULL record (so at some later point I
can filter with WHERE or so; only for timezone = 'CET' and datestyle =
'German')
CREATE OR REPLACE FUNCTION tagderdeutscheneinheit(TIMESTAMP WITH TIME ZONE)
RETURNS SETOF TIMESTAMP WITH TIME ZONE
CALLED ON NULL INPUT STABLE AS $$
DECLARE
in_ts timestamp with time zone;
rest_ts varchar(14);
yyyy smallint;
BEGIN
IF $1 IS NULL
THEN in_ts := localtimestamp(0);
ELSE in_ts := $1;
END IF;
yyyy := to_number(date_part('year',in_ts),'9999');
rest_ts := to_char(date_part('year',in_ts),'9999') || to_char(date_part('hour',in_ts),'99')
|| to_char(date_part('minute',in_ts),'99') || to_char(date_part('seconds',in_ts),'99');
SELECT CASE WHEN yyyy > 1951 AND yyyy <= 1990 THEN to_timestamp('03.10.' || rest_ts,'DD MM YYYY HH24 MI SS')
ELSE NULL
END
UNION ALL
SELECT CASE WHEN yyyy >= 1990 THEN to_timestamp('17.06.' || rest_ts,'DD MM YYYY HH24 MI SS')
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql;
what i get:
ERROR: SELECT query has no destination for result data
2.)
similar to the above function, the below have been declared; each of
them returns exactly one value of type timestamp with time zone.
CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE);
CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE)
RETURNS SETOF feiertag
CALLED ON NULL INPUT AS $$
DECLARE
in_ts timestamp with time zone;
BEGIN
IF $1 IS NULL
THEN in_ts := localtimestamp(0);
ELSE in_ts := $1;
END IF;
SELECT 'Allerheiligen ', allerheiligen(in_ts)
UNION SELECT 'Aschermittwoch ', aschermittwoch(in_ts)
...
UNION SELECT 'Tag der deutschen Einheit ', tagderdeutscheneinheit(in_ts)
UNION SELECT 'Zweiter Weihnachtstag ', zweiterweihnachtstag(in_ts) ;
END;
$$ LANGUAGE plpgsql;
a result "table" like this is what I want:
bezeichnung | datum
-----------------+-------
Allerheiligen | ....
what i get:
bruegmann@traffic_nrw=# select feiertage(NULL);
ERROR: SELECT query has no destination for result data
HINT: If you want to discard the results, use PERFORM instead.
CONTEXT: PL/pgSQL function "feiertage" line 9 at SQL statement
What I don't understand here is: this is a fixed number of records, a
composit type for setof has been declared, so what else is missing or
is wrong?
Thanks for any help,
Johannes
am 21.12.2005, um 16:54:43 +0100 mailte Johannes BrXgmann folgendes: > Hello all novices and experts, > > I didn't understand how to create a function, which returns a varying > number of records. Worse, it seems, that I didn't understand the SETOF > feature at all... Two examples: > 2.) > > similar to the above function, the below have been declared; each of > them returns exactly one value of type timestamp with time zone. > > CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE); > > CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE) > RETURNS SETOF feiertag > CALLED ON NULL INPUT AS $$ > DECLARE > in_ts timestamp with time zone; > BEGIN > IF $1 IS NULL > THEN in_ts := localtimestamp(0); > ELSE in_ts := $1; > END IF; > > SELECT 'Allerheiligen ', allerheiligen(in_ts) > UNION SELECT 'Aschermittwoch ', aschermittwoch(in_ts) > ... > UNION SELECT 'Tag der deutschen Einheit ', tagderdeutscheneinheit(in_ts) > UNION SELECT 'Zweiter Weihnachtstag ', zweiterweihnachtstag(in_ts) ; > END; > $$ LANGUAGE plpgsql; > > > a result "table" like this is what I want: > > bezeichnung | datum > -----------------+------- > Allerheiligen | .... You should return your rows ;-) Visit http://www.varlena.com/GeneralBits/26, Chapter ' Returning Sets', for a example for a SRF written in plpgsql. HTH, Andreas -- Andreas Kretschmer (Kontakt: siehe Header) Heynitz: 035242/47212, D1: 0160/7141639 GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net === Schollglas Unternehmensgruppe ===
Hello Andreas,
hello novices and experts,
first of all thank you very much for your immediate response! The hint
is great but surprising to me.
"A. Kretschmer" <andreas.kretschmer@schollglas.com> writes:
> am 21.12.2005, um 16:54:43 +0100 mailte Johannes BrXgmann folgendes:
>>
>> I didn't understand how to create a function, which returns a varying
>> number of records. Worse, it seems, that I didn't understand the SETOF
>> feature at all...
>>
>> a result "table" like this is what I want:
>>
>> bezeichnung | datum
>> -----------------+-------
>> Allerheiligen | ....
>
> You should return your rows ;-)
Thank you very much!
I always had this in mind:
,----[ ${doc}/postgresql-8.0.3/html/xfunc-sql.html ]
| 31.4.4. SQL Functions Returning Sets
|
| When an SQL function is declared as returning SETOF sometype, the
| function's final SELECT query is executed to completion, and each row
| it outputs is returned as an element of the result set.
`----[ end ]
But this is SQL isn't it, ;-)? And SQL doesn't support timestamp, does
it? (AAaaarrggghhhh...)
A new problem is now, that i still can't get it to work after all:
CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE);
CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE)
RETURNS SETOF feiertag
CALLED ON NULL INPUT AS $$
DECLARE
in_ts timestamp with time zone;
curr feiertag%ROWTYPE;
r RECORD;
BEGIN
IF $1 IS NULL
THEN in_ts := localtimestamp(0);
ELSE in_ts := $1;
END IF;
FOR r IN SELECT f.b AS b, f.d AS d
FROM (
SELECT 'Allerheiligen ' AS b, allerheiligen(in_ts) AS d
UNION SELECT 'Aschermittwoch ' AS b, aschermittwoch(in_ts) AS d
...
UNION SELECT 'Tag der deutschen Einheit ' AS b, tagderdeutscheneinheit(in_ts) AS d
UNION SELECT 'Zweiter Weihnachtstag ' AS b, zweiterweihnachtstag(in_ts) AS d) AS f
LOOP
curr.bezeichnung := r.b;
curr.datum := r.d;
RETURN NEXT curr;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
Where is the bug now?
Thanks a lot!
Johannes
Hello Andreas,
hello novices and experts,
> first of all thank you very much for your immediate response! The hint
> is great but surprising to me.
>
> "A. Kretschmer" <andreas.kretschmer@schollglas.com> writes:
>
>> am 21.12.2005, um 16:54:43 +0100 mailte Johannes BrXgmann folgendes:
>>>
>>> I didn't understand how to create a function, which returns a varying
>>> number of records. Worse, it seems, that I didn't understand the SETOF
>>> feature at all...
>>>
>>> a result "table" like this is what I want:
>>>
>>> bezeichnung | datum
>>> -----------------+-------
>>> Allerheiligen | ....
>>
>> You should return your rows ;-)
>
> Thank you very much!
>
> I always had this in mind:
>
> ,----[ ${doc}/postgresql-8.0.3/html/xfunc-sql.html ]
> | 31.4.4. SQL Functions Returning Sets
> |
> | When an SQL function is declared as returning SETOF sometype, the
> | function's final SELECT query is executed to completion, and each row
> | it outputs is returned as an element of the result set.
> `----[ end ]
>
> But this is SQL isn't it, ;-)? And SQL doesn't support timestamp, does
> it? (AAaaarrggghhhh...)
>
> A new problem is now, that i still can't get it to work after all:
>
> CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE);
>
> CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE)
> RETURNS SETOF feiertag
> CALLED ON NULL INPUT AS $$
> DECLARE
> in_ts timestamp with time zone;
> curr feiertag%ROWTYPE;
> r RECORD;
> BEGIN
> IF $1 IS NULL
> THEN in_ts := localtimestamp(0);
> ELSE in_ts := $1;
> END IF;
>
> FOR r IN SELECT f.b AS b, f.d AS d
> FROM (
> SELECT 'Allerheiligen ' AS b, allerheiligen(in_ts) AS d
> UNION SELECT 'Aschermittwoch ' AS b, aschermittwoch(in_ts) AS d
> ...
> UNION SELECT 'Tag der deutschen Einheit ' AS b, tagderdeutscheneinheit(in_ts) AS d
> UNION SELECT 'Zweiter Weihnachtstag ' AS b, zweiterweihnachtstag(in_ts) AS d) AS f
> LOOP
> curr.bezeichnung := r.b;
> curr.datum := r.d;
> RETURN NEXT curr;
> END LOOP;
> RETURN;
>
> END;
> $$ LANGUAGE plpgsql;
>
> Where is the bug now?
sorry, i missed the error message:
bruegmann@traffic_nrw=# select feiertage(NULL);
ERROR: set-valued function called in context that cannot accept a set
CONTEXT: PL/pgSQL function "feiertage" line 30 at return next
Thanks in advance,
Johannes
Johannes Brügmann <johannes@jottbee.org> schrieb:
> I always had this in mind:
>
> ,----[ ${doc}/postgresql-8.0.3/html/xfunc-sql.html ]
> | 31.4.4. SQL Functions Returning Sets
> |
> | When an SQL function is declared as returning SETOF sometype, the
> | function's final SELECT query is executed to completion, and each row
> | it outputs is returned as an element of the result set.
> `----[ end ]
If you write the function in the language 'sql', then this is right.
But in your function there are things like 'if...', so you need plpgsql.
>
> But this is SQL isn't it, ;-)? And SQL doesn't support timestamp, does
> it? (AAaaarrggghhhh...)
???
timestamp and timestamptz are valid types in SQL.
> A new problem is now, that i still can't get it to work after all:
>
> CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE);
>
> CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE)
> ...
> END;
> $$ LANGUAGE plpgsql;
>
> Where is the bug now?
I can't see a error-message, sorry ;-)
Btw.: we have a german mailing list too ;-)
HTH, Andreas
--
Really, I'm not out to destroy Microsoft. That will just be a completely
unintentional side effect. (Linus Torvalds)
Kaufbach, Saxony, Germany, Europe. N 51.05082°, E 13.56889°
"Johannes Br�gmann" <johannes@jottbee.org> writes:
> sorry, i missed the error message:
> bruegmann@traffic_nrw=# select feiertage(NULL);
> ERROR: set-valued function called in context that cannot accept a set
> CONTEXT: PL/pgSQL function "feiertage" line 30 at return next
You need to do
select * from your_function(...);
not just
select your_function(...);
regards, tom lane
Hello Andreas,
hello novices and experts,
thanks again for your immediate help!
Andreas Kretschmer <akretschmer@spamfence.net> writes:
> Johannes Brügmann <johannes@jottbee.org> schrieb:
>> I always had this in mind:
>>
>> ,----[ ${doc}/postgresql-8.0.3/html/xfunc-sql.html ]
>> | 31.4.4. SQL Functions Returning Sets
>> |
>> | When an SQL function is declared as returning SETOF sometype, the
>> | function's final SELECT query is executed to completion, and each row
>> | it outputs is returned as an element of the result set.
>> `----[ end ]
>
> If you write the function in the language 'sql', then this is right.
> But in your function there are things like 'if...', so you need plpgsql.
This is what i tried after understanding it with your help, but i got
a syntax error in the DECLARE part just before timestamptz, so i
thought the type wouldn't be supported by language 'sql'. I didn't
know that the IF control expressions where the bad guys. Maybe I try
it again in language 'sql', because IF should be replacable in what i
want.
>> But this is SQL isn't it, ;-)? And SQL doesn't support timestamp, does
>> it? (AAaaarrggghhhh...)
>
> ???
> timestamp and timestamptz are valid types in SQL.
yes, i wrote it before i thought about it; sorry.
>> A new problem is now, that i still can't get it to work after all:
>>
>> CREATE TYPE feiertag AS (bezeichnung VARCHAR(100), datum TIMESTAMP WITH TIME ZONE);
>>
>> CREATE OR REPLACE FUNCTION feiertage(TIMESTAMP WITH TIME ZONE)
>> ...
>> END;
>> $$ LANGUAGE plpgsql;
>>
>> Where is the bug now?
>
> I can't see a error-message, sorry ;-)
yes, i recognized my mistake already.. The other posting contains the solution.
> Btw.: we have a german mailing list too ;-)
Aah, next time!
Thanks you very much for your patience and the immediate help
Johannes
Hello Tom, hello novices and experts, Tom Lane <tgl@sss.pgh.pa.us> writes: > "Johannes Brügmann" <johannes@jottbee.org> writes: >> sorry, i missed the error message: > >> bruegmann@traffic_nrw=# select feiertage(NULL); >> ERROR: set-valued function called in context that cannot accept a set >> CONTEXT: PL/pgSQL function "feiertage" line 30 at return next > > You need to do > select * from your_function(...); > not just > select your_function(...); yes, that's it! Now it works, yeaaaah! Thanks a lot to you, Tom, for your immediate help! Johannes