Por que existe uma diferença de comportamento entre o uso de uma SRF (Set Returning Function) na lista SELECT e o uso de SRF na cláusula FROM?
Por exemplo, para um SRF simples retornando 2 linhas:
CREATE OR REPLACE FUNCTION gen_series(out integer, out int)
RETURNS SETOF record AS $$
SELECT 1,1
UNION
SELECT 2,2;
$$ LANGUAGE SQL;
SELECT gen_series();
retorna duas linhas de coluna única, cada uma contendo um registro:
=> gen_series
------------
(1,1)
(2,2)
(2 rows)
Considerando que SELECT * FROM gen_series();
retorna duas linhas com o registro expandido:
=> column1 | column2
---------+---------
1 | 1
2 | 2
(2 rows)
Por comparação, se o SRF estiver retornando uma única coluna, chamar o SRF na cláusula SELECT ou FROM não fará diferença. por exemplo:
=> SELECT generate_series(1,2);
generate_series
-----------------
1
2
(2 rows)
=> SELECT * FROM generate_series(1,2);
generate_series
-----------------
1
2
(2 rows)
Minhas perguntas são:
Não vejo bem por que, no segundo caso, o comportamento do SRF é diferente do primeiro caso apenas porque a tabela retornada possui uma única coluna. Esse comportamento é realmente consistente em termos de tipos, tuplas e conjuntos?
Qual é a diferença entre os dois casos que leva ao comportamento diferente?
O SRF pode ser usado como tabelas, como mostrado acima, mas as tabelas também podem ser usadas para substituir os SRFs? por exemplo
SELECT my_table;
Aparentemente, isso não pode ser feito, mas por que é SELECT my_SRF();
possível, enquanto
SELECT my_table;
não é permitido (em termos de relações e matemática)?
SELECT my_table;
não é uma sintaxe válidaRespostas:
O Postgres trata o caso simples de maneira diferente. Várias colunas são tratadas como tipo composto (linha da tabela), que é decomposta apenas com
SELECT * FROM ...
, enquanto uma única coluna do tipo escalar é tratada como apenas isso, nenhum wrapper de tipo composto adicionado. Portanto,SELECT my_SRF()
produz o mesmo queSELECT * FROM my_SRF()
no caso simples. O manual sobre funções de tabela :Concordo que isso é confuso, e você não é o primeiro a ficar confuso. (Considere a alternativa: adicionar um wrapper de tipo composto em torno de uma única coluna pode ser ainda mais confuso.)
Mas não é tão confuso quanto o que acontece quando você combina várias funções SRF na
SELECT
lista. Isso vai mudar com o Postgres 10 para sempre:A maneira segura e menos confusa para ambos os casos é mover as funções SRF para a
FROM
cláusula. Use umaLATERAL
junção se precisar consultar as colunas de outra tabela. O manual sugere:fonte