How to use RETURNS TABLE with an existing table in PostgreSQL?
PS: sorry for my comments, I was developing a complex code and I have a small error that seems a stupid PostgreSQL restriction on a "returing table" part... I was stupid, instead of concentrating and solving it, I used the internet (search engine put me here). Now, this wiki-answer is to help other readers, called by search engine and attracted by the title of the question.
Thanks to @dezso (was a correct answer) and, please all readers, you can edit this question to be more didactic, it is a Wiki.
Since PostgreSQL-v8 we can do it! We can RETURNS EXISTING_TABLE_NAME
In its Guide, in all PostgreSQL versions, from since pg v8 to current version, all have a section named "SQL Functions as Table Sources". Let's reproduce the Guide's example with some simplifications:
CREATE TABLE foo (fooid int, foosubid int, fooname text);
INSERT INTO foo VALUES (1, 1, 'Joe'), (1, 2, 'Ed'), (2, 1, 'Mary');
CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
SELECT * FROM foo WHERE fooid = $1;
$$ LANGUAGE SQL;
SELECT * FROM getfoo(1);
It is running as expected, it is perfect!
fooid | foosubid | fooname
-------+----------+---------
1 | 1 | Joe
1 | 2 | Ed
The question "How to use RETURNS TABLE with an existing table in PostgreSQL?" have a good answer since pg v8... This is the way we do it in the last 15 years, the syntax is:
RETURNS SETOF <EXISTING_TABLE_NAME>
.
Use clause TABLE as instantaneous CREATE TABLE for returning
The @tinlyx's confusion, explainded on his question, is about the use of the clause TABLE
instead of SETOF
... To think using the "PostgreSQL syntax logic", we must first remember that RETURN <EXISTING_TABLE_NAME>
is also valid, and it has the same behavior that RETURN <EXISTING_TYPE_NAME>
. Is natural to return only one row.
Next step, remember that we declare a tuple with the CREATE TABLE clause (), therefore, a good syntax to express an "instant-define-tuple table" is RETURN TABLE (), and it makes sense to return TABLE -type, which is like an array type, will return several instances (TABLE is a set of tuples).
Next step, remember that we declare a tuple with the CREATE TABLE (<tuple_description>)
clause, therefore, a good syntax to express an "instantaneous table-definition" is RETURN TABLE (<tuple_description>)
; and it makes sense to return Table-type, that is like Array-type, they return multiple instances (TABLE is a set of tuples).
The "modern thing" in PostgreSQL (!) is what @ZiggyCrueltyfreeZeitgeister showed, the RETURNS TABLE (LIKE <table_name>)
syntax.
CREATE FUNCTION getfoo2(int) RETURNS TABLE (LIKE foo) AS $$ -- working fine!
SELECT * FROM foo WHERE fooid = $1;
$$ LANGUAGE SQL;
SELECT * FROM getfoo2(1); -- same result as getfoo(1)
Many ways to do the same, a summary:
Expliciting the table name (two ways) or type name:
RETURNS SETOF <table_name>
(old but good)RETURNS TABLE (LIKE <table_name>)
(modern)RETURNS SETOF <type_name>
(afterCREATE TYPE <type_name> (<tuple_description>)
)
Implicit/generic ways, by anonymous types:
RETURNS SETOF RECORD
(generic but somethimes a problem)- (exist something as?)
RETURNS SETOF ROW?
Instantaneous table-definition:
RETURNS TABLE (<tuple_description>)
- (no
RETURNS
) usingOUT
in the parameter list.
For the last case, using our example to illustrate: CREATE FUNCTION getfoo(int, OUT fooid int, OUT foosubid int, OUT fooname text)
For dynamic and/or polymophic input you must check this explanation.
Best practice?
There are many ways to do the same, so, there are a "best one"?
As syntax I prefer the use of TABLE
, that is explicit: no confusion with "implicit RECORD", no fear of incompatibilities... But the fundamentals is in the library manage (when using table name in any way), for example when do DELETE TABLE foo CASCADE
(test it!), the function is also deleted.
The different modes are interchangeable in some circumstances, but are different. What RETURNS TABLE
is good for is described in the sentence you removed from your quote above:
This is equivalent to using one or more OUT parameters plus marking the function as returning SETOF record (or SETOF a single output parameter's type, as appropriate).
This means that CREATE FUNCTION ... RETURNS TABLE
is intended to specify a custom return type, i.e. it is equivalent to CREATE TYPE xxx_t AS ([fields...,]); CREATE FUNCTION xxx ... RETURNS SETOF xxx_t
, and also CREATE FUNCTION xxx ([in params...,] out [fields...,]) RETURNS SETOF RECORD
.
I.e., a function cannot return a table of some other table's type: use RETURNS SETOF
directly for that (as you did in the snippet in your question).