PostgreSQL: выберите из функции, которая возвращает составной тип - PullRequest
3 голосов
/ 26 ноября 2010

Как включить функцию, которая возвращает составной тип, в SELECT?
У меня составной тип:

CREATE TYPE "public"."dm_nameid" AS (
  "id" "public"."dm_int",
  "name" "public"."dm_str"
);

Также у меня есть функция, которая возвращает этот тип fn_GetLinkedProject (integer) И мне нужно сделать что-то вроде этого:

SELECT 
    p.id, p.data, p.name, 
    pl.id linked_id, pl.name linked_name
FROM tb_projects p
   left join "fn_GetLinkedProject"(p.id) pl

Как я могу это сделать?

P.S. Я прочитал эту статью.

P.P.S. Я не хочу следующий метод:

SELECT
 p.id, p.data, p.name, 
    (select pl1.id from "fn_GetLinkedProject"(p.id) pl1 ) linked_id,
    (select pl2.name from "fn_GetLinkedProject"(p.id) pl2 ) linked_name
FROM tb_projects p

1 Ответ

7 голосов
/ 13 ноября 2011

Попробуйте это демо

CREATE TYPE dm_nameid AS (
  id int
, name text); -- simplified for demo

CREATE TABLE tb_projects(
  id   integer
, data text
, name text);

INSERT INTO tb_projects VALUES
  (1, 'data_1', 'name_1')
, (2, 'data_2', 'name_2')
, (3, 'data_3', 'name_3');

CREATE function fn_getlinkedproject(integer)
  RETURNS dm_nameid AS
$func$
   SELECT id, name FROM tb_projects
   WHERE  id = ($1 % 3) + 1;
$func$ LANGUAGE sql;

Звоните:

SELECT p.id AS p_id, p.data AS p_data, p.name AS p_name
     ,(fn_getlinkedproject(p.id)).*
FROM   tb_projects p;

Лучше используйте LATERAL соединение в pg 9.3 +

SELECT p.id AS p_id, p.data AS p_data, p.name AS p_name, f.*
FROM   tb_projects p
LEFT   JOIN LATERAL fn_getlinkedproject(p.id) f ON TRUE;

Результат:

 p_id | p_data | p_name | id |  name
------+--------+--------+----+--------
    1 | data_1 | name_1 |  2 | name_2
    2 | data_2 | name_2 |  3 | name_3
    3 | data_3 | name_3 |  1 | name_1

Если вы хотите переименовать получившиеся столбцы, вам необходимо:

SELECT p.id, p.data, p.name
     ,(fn_getlinkedproject(p.id)).id   AS linked_id
     ,(fn_getlinkedproject(p.id)).name AS linked_name
FROM   tb_projects p;

Или используйте подзапрос, чтобы избежать вызова функции дважды (если функция дорогая):

SELECT p.id, p.data, p.name
    , (p.x).id AS linked_id, (p.x).name AS linked_name
FROM  (SELECT *, fn_getlinkedproject(id) AS x FROM tb_projects) p;

Или, в пг 9,3 +:

SELECT p.id AS p_id, p.data AS p_data, p.name AS p_name
     , f.id AS linked_id, f.name AS linked_name
FROM   tb_projects p
LEFT   JOIN LATERAL fn_getlinkedproject(p.id) f ON TRUE;

Результат:

 id |  data  |  name  | linked_id | linked_name
----+--------+--------+-----------+-------------
  1 | data_1 | name_1 |         2 | name_2
  2 | data_2 | name_2 |         3 | name_3
  3 | data_3 | name_3 |         1 | name_1

Протестировано с PostgreSQL 8.4 - 9.3. Вероятно, также работает с 8.2 или 8.3 (не проверено).
Обратите внимание на размещение скобок ! Это важно.
Прочитайте руководство о составных типах .

...