Noções básicas sobre a função de retorno definido (SRF) na lista SELECT

8

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:

  1. 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?

  2. Qual é a diferença entre os dois casos que leva ao comportamento diferente?

  3. 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)?

tinlyx
fonte
SELECT my_table;não é uma sintaxe válida
Mladen Uzelac

Respostas:

3

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 que SELECT * FROM my_SRF()no caso simples. O manual sobre funções de tabela :

Funções de tabela são funções que produzem um conjunto de linhas, compostas por tipos de dados base (tipos escalares) ou tipos de dados compostos (linhas da 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 SELECTlista. 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 FROMcláusula. Use uma LATERALjunção se precisar consultar as colunas de outra tabela. O manual sugere:

A LATERALsintaxe produz resultados menos surpreendentes ao chamar várias funções de retorno de conjunto e geralmente deve ser usada.

Erwin Brandstetter
fonte