Как избежать множественных ошибок функций с помощью синтаксиса (func ()). * В запросе SQL?

контекст

Когда функция возвращаетTABLE илиSETOF composite-type, как этот пример функции:

CREATE FUNCTION func(n int) returns table(i int, j bigint) as $
BEGIN
  RETURN QUERY select 1,n::bigint 
      union all select 2,n*n::bigint
      union all select 3,n*n*n::bigint;
END
$ language plpgsql;

К результатам можно получить доступ различными способами:

1)select * from func(3) произведет эти выходные столбцы:

 i | j 
---+---
 1 |  3
 2 |  9
 3 | 27

2)select func(3) будет производить только один выходной столбец типа ROW.

 func  
-------
 (1,3)
 (2,9)
 (3,27)

3)select (func(3)).* будет производить как # 1:

 i | j 
---+---
 1 |  3
 2 |  9
 3 | 27

Когда аргумент функции происходит из таблицы или подзапроса, синтаксис # 3 является единственным возможным, как в:

select N, (func(N)).* from (select 2 as N union select 3 as N) s;

или как в этом связанномответ, Если бы мы имелиLATERAL JOIN мы могли бы использовать это, но до выхода PostgreSQL 9.3 он не поддерживается, и предыдущие версии все равно будут использоваться годами.

проблема

Теперь проблема с синтаксисом # 3 заключается в том, что функция вызывается столько раз, сколько столбцов в результате. Там нет очевидной причины для этого, но это происходит. Мы можем увидеть это в версии 9.2, добавивRAISE NOTICE 'called for %', n в функции. С запросом выше, это выводит:

NOTICE:  called for 2
NOTICE:  called for 2
NOTICE:  called for 3
NOTICE:  called for 3

Теперь, если функция изменена так, чтобы она возвращала 4 столбца, вот так:

CREATE FUNCTION func(n int) returns table(i int, j bigint,k int, l int) as $
BEGIN
  raise notice 'called for %', n;
  RETURN QUERY select 1,n::bigint,1,1 
      union all select 2,n*n::bigint,1,1
      union all select 3,n*n*n::bigint,1,1;
END                                        
$ language plpgsql stable;

затем тот же запрос выводит:

NOTICE:  called for 2
NOTICE:  called for 2
NOTICE:  called for 2
NOTICE:  called for 2
NOTICE:  called for 3
NOTICE:  called for 3
NOTICE:  called for 3
NOTICE:  called for 3

Потребовалось 2 вызова функций, фактически было сделано 8. Соотношение - это количество выходных столбцов.

С синтаксисом № 2, который дает тот же результат, за исключением разметки выходных столбцов, эти множественные вызовы не происходят

select N,func(N) from (select 2 as N union select 3 as N) s;

дает:

NOTICE:  called for 2
NOTICE:  called for 3

затем следуют 6 строк:

 n |    func    
---+------------
 2 | (1,2,1,1)
 2 | (2,4,1,1)
 2 | (3,8,1,1)
 3 | (1,3,1,1)
 3 | (2,9,1,1)
 3 | (3,27,1,1)
Вопросов

Существует ли синтаксис или конструкция с 9.2, которая могла бы достичь ожидаемого результата, выполняя только минимальные требуемые вызовы функций?

Бонусный вопрос: почему множественные оценки вообще происходят?

Ответы на вопрос(1)

Ваш ответ на вопрос