Search code examples
sqlpostgresqlpostgresql-9.3

Passing more than one row (query result) into a function


I have a SELECT from a function (with ordinary, not SETOF argument). However, I would like to call the function multiple times within the query (and then to aggregate the results), feeding it with a CTE.

Some (example) code:

CREATE TYPE MY_TYPE AS ( a integer, b integer );

CREATE OR REPLACE FUNCTION foo( foobar INTEGER ) 
RETURNS MY_TYPE AS $$
BEGIN
  -- do something, return MY_TYPE
END;  
$$ LANGUAGE plpgsql;

WITH x AS (
  SELECT a FROM bar WHERE b = 1
)
SELECT min(a) FROM foo( (SELECT a FROM x) ) f

This doesn't work, I get following error message:

ERROR:  more than one row returned by a subquery used as an expression

Now I wonder how to rewrite the query. I could loop over the CTE results, then call the function with one input value at a time, store results in a column, and finally find the minimum - this feels clumsy and should be quite slow. Another approach would be to wrap my function in another, set-returning and with array parameter. But this just pushes the problem away: I don't know how to simply wrap it.

What seems fine is to rewrite the function to the SETOF form. Still, this is a workaround, and learning how to call ordinary functions with more than one row returned by a query (if it is possible) would be better.


Solution

  • Try this:

    SELECT min(f.a)
      FROM bar  
      CROSS JOIN foo(bar.a) f
      WHERE bar.b = 1