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

Devolver filas SETOF desde la función PostgreSQL

Función de desinfección

Lo que tiene actualmente se puede simplificar/desinfectar 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$;

Solo necesita instancias adicionales de BEGIN ... END en el cuerpo de la función para iniciar bloques de código separados con su propio alcance, lo que rara vez se necesita.

El operador de concatenación SQL estándar es || . + es una adición "creativa" de su proveedor anterior.

No use identificadores de mayúsculas y minúsculas CaMeL a menos que los entrecomilla. Es mejor no usarlos en absoluto Ver:

  • ¿Los nombres de las columnas de PostgreSQL distinguen entre mayúsculas y minúsculas?

varchar(4000) también se adapta a una limitación específica de SQL Server. No tiene un significado específico en Postgres. Solo use varchar(4000) si realmente necesita un límite de 4000 caracteres. Simplemente usaría text - excepto que no necesitamos ninguna variable en absoluto aquí, después de simplificar la función.

Si no ha utilizado format() , sin embargo, consulte el manual aquí.

Tipo de retorno

Ahora, para su pregunta real:el tipo de devolución para una consulta dinámica puede ser complicado ya que SQL requiere que se declare en el momento de la llamada a más tardar. Si tiene una tabla, vista o tipo compuesto en su base de datos que ya coincide con la lista de definición de columna, puede usar eso:

CREATE FUNCTION foo()
  RETURNS SETOF my_view AS
...

De lo contrario, deletree la lista de definición de columna sin (más simple) RETURNS TABLE :

CREATE FUNCTION foo()
  RETURNS TABLE (col1 int, col2 text, ...) AS
...

Si está creando el tipo de fila sobre la marcha, puede devolver registros anónimos:

CREATE FUNCTION foo()
  RETURNS SETOF record AS
...

Pero luego debe proporcionar una lista de definición de columna con cada llamada, por lo que casi nunca uso eso.

Yo no usaría SELECT * para empezar. Utilice una lista definitiva de columnas para devolver y declare su tipo de devolución en consecuencia:

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 la consulta en su cliente para empezar, en lugar de usar una función.

Primero debe comprender los conceptos básicos:

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

Luego, hay opciones más avanzadas con tipos polimórficos, que le permiten pasar el tipo de retorno en el momento de la llamada. Más en el último capítulo de:

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