Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
537 views
in Technique[技术] by (71.8m points)

sql - How can you expand a "condensed" PostgreSQL row into separate columns?

I have a function which returns a table.

If you run SELECT * FROM some_function(12345) the result is:

object_id | name
----------------
    12345 | "B"

If you run SELECT some_function(12345) the result is:

some_function
-------------
(12345,"B")

The problem is that I want the original form (so that I can access individual column values), but have the argument to some_function() come from a column in a table. I can execute SELECT some_function(thing_id) FROM things but this returns:

some_function
-------------
(12345,"B")
(12346,"C")
(12347,"D")

Whereas what I want returned is:

object_id | name
----------------
    12345 | "B"
    12346 | "C"
    12347 | "D"

So how can one "unnest" or "expand" such a condensed row?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

9.3 and above: lateral query

In PostgreSQL 9.3 or newer use an implicit lateral query:

SELECT f.* FROM things t, some_function(t.thing_id) f;

Prefer this formulation for all new queries. The above is the standard formulation.

It also works properly with functions that RETURNS TABLE or RETURNS SETOF RECORD as well as funcs with out-params that RETURNS RECORD.

It's shorthand for:

SELECT f.*
FROM things t
CROSS JOIN LATERAL some_function(t.thing_id) f;

Pre-9.3: wildcard expansion (with care)

Prior versions, causes multiple-evaluation of some_function, does not work if some_function returns a set, do not use this:

SELECT (some_function(thing_id)).* FROM things;

Prior versions, avoids multiple-evaluation of some_function using a second layer of indirection. Only use this if you must support quite old PostgreSQL versions.

SELECT (f).*
FROM (
  SELECT some_function(thing_id) f
  FROM things
) sub(f);

Demo:

Setup:

CREATE FUNCTION some_function(i IN integer, x OUT integer, y OUT text, z OUT text) RETURNS record LANGUAGE plpgsql AS $$
BEGIN
  RAISE NOTICE 'evaluated with %',i;
  x := i;
  y := i::text;
  z := 'dummy';
  RETURN;
END;
$$;

create table things(thing_id integer);
insert into things(thing_id) values (1),(2),(3);

test run:

demo=>     SELECT f.* FROM things t, some_function(t.thing_id) f;
NOTICE:  evaluated with 1
NOTICE:  evaluated with 2
NOTICE:  evaluated with 3
 x | y |   z   
---+---+-------
 1 | 1 | dummy
 2 | 2 | dummy
 3 | 3 | dummy
(3 rows)

demo=>     SELECT (some_function(thing_id)).* FROM things;
NOTICE:  evaluated with 1
NOTICE:  evaluated with 1

NOTICE:  evaluated with 1
NOTICE:  evaluated with 2
NOTICE:  evaluated with 2
NOTICE:  evaluated with 2
NOTICE:  evaluated with 3
NOTICE:  evaluated with 3
NOTICE:  evaluated with 3
 x | y |   z   
---+---+-------
 1 | 1 | dummy
 2 | 2 | dummy
 3 | 3 | dummy
(3 rows)

demo=>  SELECT (f).*
    FROM (
      SELECT some_function(thing_id) f
      FROM things
    ) sub(f);
NOTICE:  evaluated with 1
NOTICE:  evaluated with 2
NOTICE:  evaluated with 3
 x | y |   z   
---+---+-------
 1 | 1 | dummy
 2 | 2 | dummy
 3 | 3 | dummy
(3 rows)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...