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

ORDEN dinámico POR y ASC / DESC en una función plpgsql

Yo lo haría así:

CREATE OR REPLACE FUNCTION list(
      _category varchar(100)
    , _limit int
    , _offset int
    , _order_by varchar(100)
    , _order_asc_desc text = 'ASC')  -- last param with default value
  RETURNS TABLE(id int, name varchar, clientname varchar, totalcount bigint)
  LANGUAGE plpgsql AS
$func$
DECLARE
   _empty text := '';
BEGIN
   -- Assert valid _order_asc_desc
   IF upper(_order_asc_desc) IN ('ASC', 'DESC', 'ASCENDING', 'DESCENDING') THEN
      -- proceed
   ELSE
      RAISE EXCEPTION 'Unexpected value for parameter _order_asc_desc.
                       Allowed: ASC, DESC, ASCENDING, DESCENDING. Default: ASC';
   END IF;
   
   RETURN QUERY EXECUTE format(
     'SELECT id, name, clientname, count(*) OVER() AS full_count
      FROM   design_list
      WHERE ($1 = $2 OR category ILIKE $1) 
      ORDER  BY %I %s
      LIMIT  %s
      OFFSET %s'
    , _order_by, _order_asc_desc, _limit, _offset)
   USING _category, _empty;
END
$func$;

Característica principal:use format() para concatenar de forma segura y elegante su cadena de consulta. Relacionado:

ASC / DESC (o ASCENDING / DESCENDING ) son palabras clave fijas. Agregué una verificación manual (IF ... ) y luego concatenar con un simple %s . Ese es uno manera de hacer valer la entrada legal. Para mayor comodidad, agregué un mensaje de error para entradas inesperadas y un valor predeterminado de parámetro, por lo que la función tiene como valor predeterminado ASC si se omite el último parámetro en la llamada. Relacionado:

Abordar Pavel's valid comentario , concateno _limit y _offset directamente, por lo que la consulta ya está planificada con esos parámetros.

_limit y _offset son integer parámetros, por lo que podemos usar %s simple sin el peligro de inyección SQL. Es posible que desee afirmar valores razonables (excluir valores negativos y valores demasiado altos) antes de concatenar...

Otras notas:
  • Utilice una convención de nomenclatura coherente. Prefijé todos los parámetros y variables con un guión bajo _ , no solo algunos .

  • No usar calificación de tabla dentro de EXECUTE , ya que solo hay una tabla involucrada y el EXECUTE tiene su alcance separado.

  • Cambié el nombre de algunos parámetros para aclarar. _order_by en lugar de _sort_by; _order_asc_desc en lugar de _order .