PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Retornar linhas SETOF da função PostgreSQL

Função de higienização


O que você tem atualmente pode ser simplificado / higienizado para:
CREATE OR REPLACE FUNCTION func_a (username text = '', databaseobject text = '')
  RETURNS ????
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE
   format ('SELECT * FROM %s v1 LEFT JOIN %I v2 USING (id)'
         , CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
         , databaseobject);
END
$func$;

Você só precisa de instâncias adicionais de BEGIN ... END no corpo da função para iniciar blocos de código separados com seu próprio escopo, o que raramente é necessário.

O operador de concatenação SQL padrão é || . + é uma adição "criativa" do seu antigo fornecedor.

Não use identificadores de maiúsculas e minúsculas CaMeL, a menos que você os coloque entre aspas duplas. Melhor não usá-los Veja:
  • Os nomes das colunas do PostgreSQL diferenciam maiúsculas de minúsculas?

varchar(4000) também é adaptado a uma limitação específica do SQL Server. Não tem significado específico no Postgres. Use apenas varchar(4000) se você realmente precisa de um limite de 4000 caracteres. Eu usaria apenas text - exceto que não precisamos de nenhuma variável de forma alguma aqui, depois de simplificar a função.

Se você não usou format() , ainda, consulte o manual aqui.

Tipo de retorno


Agora, para sua pergunta real:O tipo de retorno para uma consulta dinâmica pode ser complicado, pois o SQL exige que seja declarado no momento da chamada. Se você tiver uma tabela ou exibição ou tipo composto em seu banco de dados que já corresponde à lista de definição de coluna, basta usar isso:
CREATE FUNCTION foo()
  RETURNS SETOF my_view AS
...

Caso contrário, soletre a lista de definição de coluna sem com (mais simples) RETURNS TABLE :
CREATE FUNCTION foo()
  RETURNS TABLE (col1 int, col2 text, ...) AS
...

Se você estiver criando o tipo de linha à medida que avança, pode retornar registros anônimos:
CREATE FUNCTION foo()
  RETURNS SETOF record AS
...

Mas então você tem que fornecer uma lista de definição de coluna com cada chamada, então eu quase nunca uso isso.

Eu não usaria SELECT * começar com. Use uma lista definitiva de colunas para retornar e declare seu tipo de retorno de acordo:
CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
  RETURNS TABLE(col1 int, col2 text, col3 date)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE
   format ($f$SELECT v1.col1, v1.col2, v2.col3
              FROM %s v1 LEFT JOIN %I v2 USING (id)$f$
         , CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
         , databaseobject);
END
$func$;

Para consultas completamente dinâmicas, considere construir a consulta em seu cliente para começar, em vez de usar uma função.

Você precisa entender o básico primeiro:
  • Refatorar uma função PL/pgSQL para retornar a saída de várias consultas SELECT
  • PL/pgSQL no manual do Postgres

Depois, há opções mais avançadas com tipos polimórficos, que permitem passar o tipo de retorno na hora da chamada. Mais no último capítulo de:
  • Refatorar uma função PL/pgSQL para retornar a saída de várias consultas SELECT