From: | Merlin Moncure <mmoncure(at)gmail(dot)com> |
---|---|
To: | Ondrej Ivanič <ondrej(dot)ivanic(at)gmail(dot)com> |
Cc: | pgsql-general(at)postgresql(dot)org |
Subject: | Re: table / query as a prameter for PL/pgSQL function |
Date: | 2011-08-08 17:23:39 |
Message-ID: | CAHyXU0yfaedOyK+OmUSrXDoWjj0ET9PWUYhZNwKPE91RThPshA@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
2011/8/7 Ondrej Ivanič <ondrej(dot)ivanic(at)gmail(dot)com>:
> Hi,
>
> It is possible to pass query result (or cursor?) as function
> parameter? I need a function which emits zero or more rows per input
> row (map function from map&reduce paradigm). Function returns record
> (or array): (value1, value2, value3)
> I've tried the following:
>
> 1) create or replace function test (r record) returns setof record as $$ ...
> Doesn't work: PL/pgSQL functions cannot accept type record
>
> 2) pass query as text parameter and open no scroll cursor inside the function
> It works but it's ugly.
>
> 3) hardcode the query inside function
> Similar to (2) and looks better but I need several functions with
> different queries inside:
> ...
> for r in (query) loop
> ...
> end loop;
> ...
>
> 4) use function in "select" clause:
> select my_map_func(col1, col2, col3, col4) from ... -- the rest of the query
> In this case I wasn't able figure out how to access record members
> returned by the function:
>
> select ?, ?, ?, count(*) from (
> select my_map_func(col1, col2, col3, col4) as map_func_result from ...
> ) as map
> group by 1, 2, 3
>
> The '?' should be something like map.map_func_result.value1 (both
> map.value1 and map_func_result.value1 doesn't not work). If function
> returns array then I can access value1 by using map_func_result[1]
>
> Is there a better way how to solve this? I'm kind of satisfied with 4
> (maybe 3) but it is little bit cumbersome
You have a few of different methods for passing sets between functions.
1) refcursor as David noted. reasonably fast. however, I find the
'FETCH' mechanic a little inflexible.
2) stage data to TABLE/TEMP TABLE; extremely flexible, but can be a
headache because a non temp table can get thrashed pretty hard a and a
'TEMP' can cause severe function plan invalidation issues if you're
not careful
3) arrays of composites -- the most flexible and very fast for *small*
amounts of records (say less than 10,000):
#3 is my favorite method unless the data being passed is very large.
Here is an example of it in use:
CREATE TYPE foo_t as (a int, b text);
CREATE FUNCTION get_foos() RETURNS SETOF foo_t AS
$$
BEGIN
RETURN QUERY SELECT 1, 'abc' UNION ALL SELECT 2, 'def';
END;
$$ LANGUAGE PLPGSQL;
CREATE FUNCTION do_foos(_foos foo_t[]) returns VOID AS
$$
DECLARE
f foo_t;
BEGIN
FOR f in SELECT * FROM UNNEST(_foos)
LOOP
RAISE NOTICE '% %', f.a, f.b;
END LOOP;
END;
$$ LANGUAGE PLPGSQL;
postgres=# SELECT do_foos(ARRAY(SELECT (a,b)::foo_t FROM get_foos()));
NOTICE: 1 abc
NOTICE: 2 def
do_foos
---------
(1 row)
Also, if you are deploying vs 9.1, be sure to check out Pavel's
for-in-array which is better method to do the unnest() which expands
the array.
merlin
From | Date | Subject | |
---|---|---|---|
Next Message | pasman pasmański | 2011-08-08 20:01:58 | Re: Problem with planner |
Previous Message | hubert depesz lubaczewski | 2011-08-08 16:53:17 | Re: Problem with planner |