Functions can not to return individual items of a

2019-09-19 04:11发布

问题:

Basic things as struct in C data types, exist in all popular languages, and is expected that functions, of these languages, also can return a struct... And, by an orthogonality principle, is expected you can access the returned struct itens.

PostgreSQL, nevertheless, did not offer access to the struct itens of a FUNCTION ... RETURNS RECORD. It is correct?

But programmers use PostgreSQL without complaining... There are a simple and intuitive workaround?


Similar question: PostgreSQL v9.X have real "array of record"?


Illustrating by typical cases

 CREATE FUNCTION foo(int) RETURNS RECORD AS $$ 
      SELECT $1 as a, 'Hello #'||$1 as b; 
 $$ LANGUAGE SQL;

 SELECT foo(6);       -- works, but I need only one item

Access of record itens in a SQL context:

 SELECT (foo(6)).a;   -- NOT works (but no ambiguity!)

 -- For syntax discussion:
 WITH f AS (SELECT foo(6) as r) SELECT r.a FROM f; -- NOT works
 -- ambiguous syntax; confused r with table, in "f.r.a", f with schema 
 -- perhaps r['a'] would be a good syntax solution

Access of record itens in a PLpgSQL context:

How to say x:=(foo(6)).a or y:=foo(6); x:=y.a? Now there are some expected behaviuor, in PLpgSQL, at least "named record" is permitted:

CREATE FUNCTION bar() RETURNS text AS $F$ 
DECLARE 
   tmp record;
   s text;
BEGIN 
   -- s:=(foo(7)).b;  NOT WORKS, is like an "anonymous record" (not permitted)
   tmp := foo(6); 
   s:=tmp.b;  -- IT WORKS!! is like a "named record" (permitted)
   RETURN s||'! '||tmp.a;  --  ...works accessing any other individual itens
END;
$F$ LANGUAGE plpgsql IMMUTABLE;

回答1:

If you use the more flexible returns table instead of (the somewhat outdated) returns record, then things get really easy:

CREATE FUNCTION foo(int) RETURNS table (a int, b text) 
AS 
$$ 
  SELECT $1 as a, 'Hello #'||$1 as b; 
$ LANGUAGE SQL;

now you can use:

select b
from foo(6);

If you are concerned about "tables" vs. "records" you can also define a type to overcome the additional result set definition:

create type foo_return as (a int, b text);
CREATE FUNCTION foo(int) RETURNS foo_return
AS 
$$ 
  SELECT $1, 'Hello #'||$1;
$$ LANGUAGE SQL;

You can still the above select then:

select b
from foo(6);

A third maybe more "C" like approach would be to use out parameters (as shown in the manual)

CREATE FUNCTION foo(p1 int, out a int, out b text)
AS
$$ 
  SELECT $1, 'Hello #'||$1;
$$ 
LANGUAGE SQL;

Then you don't need a from :

select (foo(1)).b;


回答2:

Is this simple and intuitive?

select a 
from foo(6) s(a int, b text);