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

Função para retornar um conjunto dinâmico de colunas para determinada tabela

Solução para o caso simples


Conforme explicado nas respostas referenciadas abaixo, você pode usar tipos registrados (linha) e, assim, declarar implicitamente o tipo de retorno de uma função polimórfica:
CREATE OR REPLACE FUNCTION public.get_table(_tbl_type anyelement)
  RETURNS SETOF anyelement AS
$func$
BEGIN
   RETURN QUERY EXECUTE format('TABLE %s', pg_typeof(_tbl_type));
END
$func$ LANGUAGE plpgsql;

Ligar:
SELECT * FROM public.get_table(NULL::public.users);  -- note the syntax!

Retorna a tabela completa (com todas as colunas do usuário).

Espere! Como?

Explicação detalhada nesta resposta relacionada, capítulo"Vários tipos de tabela completa" :
  • Refatorar uma função PL/pgSQL para retornar a saída de várias consultas SELECT

TABLE foo é a abreviação de SELECT * FROM foo :
  • Existe um atalho para SELECT * FROM?

2 passos para o tipo de retorno completamente dinâmico


Mas o que você está tentando fazer é estritamente impossível em um único Comando SQL.

Quero passar schema_name e table_name como parâmetros para funcionar e obter a lista de registros, de acordo com column_visible campo em public.fields tabela.

Não há uma maneira direta de retornar uma seleção arbitrária de colunas (tipo de retorno não conhecido no momento da chamada) de uma função - ou qualquer Comando SQL. O SQL exige saber número, nomes e tipos de colunas resultantes no momento da chamada. Mais no 2º capítulo desta resposta relacionada:
  • Como gerar um CROSS JOIN dinâmico onde a definição da tabela resultante é desconhecida?

Existem várias soluções alternativas . Você pode envolver o resultado em um dos tipos de documento padrão (json , jsonb , hstore , xml ).

Ou você gera a consulta com uma chamada de função e executa o resultado com a próxima:
CREATE OR REPLACE FUNCTION public.generate_get_table(_schema_name text, _table_name text)
  RETURNS text AS
$func$
   SELECT format('SELECT %s FROM %I.%I'
               , string_agg(quote_ident(column_name), ', ')
               , schema_name
               , table_name)
   FROM   fields
   WHERE  column_visible
   AND    schema_name = _schema_name 
   AND    table_name  = _table_name
   GROUP  BY schema_name, table_name
   ORDER  BY schema_name, table_name;
$func$  LANGUAGE sql;

Ligar:
SELECT public.generate_get_table('public', 'users');

Isso cria uma consulta do formulário:
SELECT usr_id, usr FROM public.users;

Execute-o na 2ª etapa. (Você pode querer adicionar números de coluna e ordenar colunas.)
Ou anexe \gexec no psql para executar o valor de retorno imediatamente. Ver:

Como forçar a avaliação da subconsulta antes de ingressar/enviar para servidor externo

Certifique-se de se defender contra injeção de SQL:
  • INSERIR com o nome da tabela dinâmica na função de gatilho
  • Definir nomes de tabelas e colunas como argumentos em uma função plpgsql?
Apartes
varchar(100) não faz muito sentido para identificadores, que são limitados a 63 caracteres no Postgres padrão:
  • Máximo de caracteres em rótulos (nomes de tabelas, colunas, etc.)

Se você entender como o tipo de identificador de objeto regclass funciona, você pode substituir o esquema e o nome da tabela por um único regclass coluna.