3

I am using PostgreSQL 8.4 and I want to create a function that returns a query with many rows.
The following function does not work:

create function get_names(varchar) returns setof record AS $$
declare
    tname alias for $1;
    res setof record;
begin
    select * into res from mytable where name = tname;
    return res;
end;
$$ LANGUAGE plpgsql;

The type record only allows single row.

How to return an entire query? I want to use functions as query templates.

7
  • As always, the version number of PostgreSQL would help. :) Commented Sep 25, 2011 at 21:28
  • Please note that -though esthetically pleasing- set-of-rows functions tend to perform badly in real life. The point is that they will not be 'broken up' by the query optimiser. A simple query like "select from f() where not exists (select ... from f())" can lead two two, maybe even three sort steps. Use with care. Commented Sep 25, 2011 at 21:44
  • @wildplasser: While that can happen if you actually nest table functions, they do perform perfectly fast as long as you don't. Faster than the query itself, actually, because the query plan can be cached. Commented Sep 25, 2011 at 21:52
  • @Erwin Brandstetter: Yes and no. Performed as a singleton, they may spare you the compilation and planning costs; used in combination with other "real" query elements, they can be disastrous, causing too many avoidable scans and sort steps. Commented Sep 25, 2011 at 22:01
  • @wildplasser: "in combination with other query elements" = to nest. Is there any other way? I don't see a downside if I use a couple of table functions sequentially inside a transaction, or am I missing something here? Commented Sep 25, 2011 at 22:25

1 Answer 1

6
CREATE OR REPLACE FUNCTION get_names(_tname varchar)
  RETURNS TABLE (col_a integer, col_b text) AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.col_a, t.col_b  -- must match RETURNS TABLE
   FROM   mytable t
   WHERE  t.name = _tname;    
END
$func$  LANGUAGE plpgsql;

Call like this:

SELECT * FROM get_names('name')

Major points:

  • Use RETURNS TABLE, so you don't have to provide a list of column names with every call.

  • Use RETURN QUERY, much simpler.

  • Table-qualify column names to avoid naming conflicts with identically named OUT parameters (including columns declared with RETURNS TABLE).

  • Use a named variable instead of ALIAS. Simpler, doing the same, and it's the preferred way.

  • A simple function like this could also be written in LANGUAGE sql:

CREATE OR REPLACE FUNCTION get_names(_tname varchar)
  RETURNS TABLE (col_a integer, col_b text) AS
$func$
SELECT t.col_a, t.col_b  --, more columns - must match RETURNS above
FROM   mytable t
WHERE  t.name = $1;
$func$ LANGUAGE sql;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.