Da documentação do PostgreSQL aqui :
Existe outra maneira de declarar uma função como retornando um conjunto, que é usar a sintaxe RETURNS TABLE(columns). ... Essa notação é especificada em versões recentes do padrão SQL e, portanto, pode ser mais portátil do que usar SETOF.
Isso soa como se RETURNS TABLE
fosse um estilo mais novo e portátil para retornar várias linhas. Mas não tenho certeza se as duas sintaxes são equivalentes.
Eu queria saber se podemos realmente usar RETURNS TABLE
para substituir RETURNS SETOF
?
Em particular, um caso que não descobri é: se tivermos uma tabela existente foo
e seu tipo composto associado, como podemos usá-la em RETURNS TABLE
?
Usando o exemplo do link acima, o seguinte pode ser reescrito usando RETURNS TABLE
:
CREATE TABLE foo (fooid int, foosubid int, fooname text);
CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
SELECT * FROM foo WHERE fooid = $1;
$$ LANGUAGE SQL;
Até agora, tentei usar RETURNS TABLE (foo.*)
e RETURNS TABLE (foo)
, o que não funcionou.
PS: desculpe meus comentários, estava desenvolvendo um código complexo e estou com um pequeno erro que parece uma restrição estúpida do PostgreSQL em uma parte de "tabela de retorno"... Fui estúpido, ao invés de me concentrar e resolver, usei a internet (mecanismo de busca me colocou aqui). Agora, esta wiki-resposta é para ajudar outros leitores, chamados pelo buscador e atraídos pelo título da pergunta.
Obrigado a @dezso (foi uma resposta correta) e, por favor, todos os leitores, você pode editar esta pergunta para ser mais didática, é um Wiki.
Desde o PostgreSQL-v8 podemos fazer isso! Podemos RETURNS EXISTING_TABLE_NAME
Em seu Guia, em todas as versões do PostgreSQL, desde pg v8 até a versão atual , todas possuem uma seção chamada "Funções SQL como Fontes de Tabelas" . Vamos reproduzir o exemplo do Guia com algumas simplificações:
Está funcionando como esperado, está perfeito!
A pergunta "Como usar RETURNS TABLE com uma tabela existente no PostgreSQL?" tenho uma boa resposta desde pg v8... É assim que fazemos nos últimos 15 anos, a sintaxe é:
RETURNS SETOF <EXISTING_TABLE_NAME>
.Use a cláusula TABLE como CREATE TABLE instantâneo para retornar
A confusão do @tinlyx, explicada na pergunta dele, é sobre o uso da cláusula ao
TABLE
invés deSETOF
... Para pensarmos usando a "lógica da sintaxe do PostgreSQL", devemos primeiro lembrar que elaRETURN <EXISTING_TABLE_NAME>
também é válida, e tem o mesmo comportamento queRETURN <EXISTING_TYPE_NAME>
. É natural retornar apenas uma linha.Próximo passo, lembre-se que declaramos uma tupla com a cláusula CREATE TABLE (<tuple_description>), portanto, uma boa sintaxe para expressar uma "tabela de definição instantânea de tupla" é RETURN TABLE (<tuple_description>), e faz sentido return TABLE -type, que é como um tipo de array, retornará várias instâncias (TABLE é um conjunto de tuplas).
Próximo passo, lembre-se que declaramos uma tupla com a
CREATE TABLE (<tuple_description>)
cláusula, portanto, uma boa sintaxe para expressar uma "definição de tabela instantânea" éRETURN TABLE (<tuple_description>)
; e faz sentido retornar o tipo Table, que é como o tipo Array, eles retornam várias instâncias (TABLE é um conjunto de tuplas).A "coisa moderna" no PostgreSQL (!) é o que @ZiggyCrueltyfreeZeitgeister mostrou, a
RETURNS TABLE (LIKE <table_name>)
sintaxe.Muitas maneiras de fazer o mesmo, um resumo:
Explicando o nome da tabela (duas maneiras) ou o nome do tipo:
RETURNS TABLE (LIKE <table_name>)
(moderno e bom)RETURNS SETOF <table_name>
(velho mas bom)RETURNS SETOF <type_name>
(depoisCREATE TYPE <type_name> (<tuple_description>)
)Formas implícitas/genéricas, por tipos anônimos:
RETURNS SETOF RECORD
(genérico, mas às vezes um problema)RETURNS SETOF ROW?
Definição de tabela instantânea:
RETURNS TABLE (<tuple_description>)
RETURNS
) usandoOUT
na lista de parâmetros.Para o último caso, usando nosso exemplo para ilustrar:
CREATE FUNCTION getfoo(int, OUT fooid int, OUT foosubid int, OUT fooname text)
Para entradas dinâmicas e/ou polimóficas, você deve verificar esta explicação .
Melhor prática?
Existem muitas maneiras de fazer o mesmo, então, existe uma "melhor"?
Como sintaxe prefiro o uso de
RETURNS TABLE (LIKE <table_name>)
, que é explícito: sem confusão com "REGISTRO implícito", sem medo de incompatibilidades...Importante para gerenciamento de bibliotecas,
DROP TABLE foo CASCADE
vai largar também a função: em qualquer sintaxe (returns table
oureturns setof
) o PostgreSQL fará um bom trabalho.Os diferentes modos são intercambiáveis em algumas circunstâncias, mas são diferentes. O que
RETURNS TABLE
é bom está descrito na frase que você removeu de sua citação acima:Isso significa que
CREATE FUNCTION ... RETURNS TABLE
se destina a especificar um tipo de retorno personalizado, ou seja, é equivalente aCREATE TYPE xxx_t AS ([fields...,]); CREATE FUNCTION xxx ... RETURNS SETOF xxx_t
, e tambémCREATE FUNCTION xxx ([in params...,] out [fields...,]) RETURNS SETOF RECORD
.Ou seja, uma função não pode retornar uma tabela do tipo de outra tabela: use
RETURNS SETOF
diretamente para isso (como você fez no trecho da sua pergunta).