PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

ORDER BY dinamico e ASC / DESC in una funzione plpgsql

Lo farei così:

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$;

Funzionalità principale:usa format() per concatenare in modo sicuro ed elegante la stringa di query. Correlati:

ASC / DESC (o ASCENDING / DESCENDING ) sono parole chiave fisse. Ho aggiunto un controllo manuale (IF ... ) e successivamente concatenare con un semplice %s . Questo è uno modo per far valere un contributo legale. Per comodità, ho aggiunto un messaggio di errore per input imprevisto e un parametro predefinito, quindi la funzione è impostata su ASC se l'ultimo parametro viene omesso nella chiamata. Correlati:

Indirizzamento Pavel è valido commenta , concateno _limit e _offset direttamente, quindi la query è già pianificata con quei parametri.

_limit e _offset sono integer parametri, quindi possiamo usare un semplice %s senza il pericolo di SQL injection. Potresti voler affermare valori ragionevoli (escludere valori negativi e valori troppo alti) prima di concatenare ...

Altre note:
  • Usa una convenzione di denominazione coerente. Ho prefissato tutti i parametri e le variabili con un trattino basso _ , non solo alcuni .

  • Non utilizza la qualificazione della tabella all'interno di EXECUTE , poiché è coinvolta solo una singola tabella e EXECUTE ha un ambito separato.

  • Ho rinominato alcuni parametri per chiarire. _order_by invece di _sort_by; _order_asc_desc invece di _order .