sql >> Base de Datos >  >> RDS >> PostgreSQL

Función para devolver un conjunto dinámico de columnas para una tabla dada

Solución para el caso simple

Como se explica en las respuestas a las que se hace referencia a continuación, puede usar tipos registrados (fila) y, por lo tanto, declarar implícitamente el tipo de retorno de una función 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;

Llamar:

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

Devuelve la tabla completa (con todas las columnas de usuario).

¡Espera! ¿Cómo?

Explicación detallada en esta respuesta relacionada, capítulo "Varios tipos de tablas completas" :

  • Refactorice una función PL/pgSQL para devolver el resultado de varias consultas SELECT

TABLE foo es la abreviatura de SELECT * FROM foo :

  • ¿Existe un atajo para SELECCIONAR * DESDE?

2 pasos para un tipo de retorno completamente dinámico

Pero lo que intenta hacer es estrictamente imposible en un sencillo Comando SQL.

Quiero pasar schema_name y table_name como parámetros para funcionar y obtener la lista de registros, según column_visible campo en public.fields mesa.

No hay una forma directa de devolver una selección arbitraria de columnas (el tipo de devolución no se conoce en el momento de la llamada) desde una función, o cualquiera Comando SQL. SQL exige conocer el número, los nombres y los tipos de columnas resultantes en el momento de la llamada. Más en el segundo capítulo de esta respuesta relacionada:

  • ¿Cómo genero un CROSS JOIN pivotado donde se desconoce la definición de la tabla resultante?

Hay varias soluciones alternativas . Puede envolver el resultado en uno de los tipos de documentos estándar (json , jsonb , hstore , xml ).

O generas la consulta con una llamada de función y ejecutas el resultado con la siguiente:

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;

Llamar:

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

Esto crea una consulta de la forma:

SELECT usr_id, usr FROM public.users;

Ejecutarlo en el segundo paso. (Es posible que desee agregar números de columna y ordenar columnas).
O agregue \gexec en psql para ejecutar el valor devuelto inmediatamente. Ver:

Cómo forzar la evaluación de la subconsulta antes de unirse/presionar hacia un servidor externo

Asegúrese de defenderse contra la inyección SQL:

  • INSERTAR con el nombre de la tabla dinámica en la función de activación
  • ¿Definir nombres de tablas y columnas como argumentos en una función plpgsql?
Apartes

varchar(100) no tiene mucho sentido para los identificadores, que están limitados a 63 caracteres en Postgres estándar:

  • Caracteres máximos en las etiquetas (nombres de tablas, columnas, etc.)

Si entiende cómo el tipo de identificador de objeto regclass funciona, puede reemplazar el esquema y el nombre de la tabla con un solo regclass columna.