PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Dynamisches ORDER BY und ASC / DESC in einer plpgsql-Funktion

Ich würde es so machen:

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

Kernfunktion:Verwenden Sie das Format format() um Ihre Abfragezeichenfolge sicher und elegant zu verketten. Verwandte:

ASC / DESC (oder ASCENDING / DESCENDING ) sind feste Schlüsselwörter. Ich habe eine manuelle Prüfung hinzugefügt (IF ... ) und später mit einem einfachen %s verketten . Das ist eins Möglichkeit zur Geltendmachung von Rechtsansprüchen. Der Einfachheit halber habe ich eine Fehlermeldung für unerwartete Eingaben und einen Parameterstandard hinzugefügt, sodass die Funktion standardmäßig auf ASC gesetzt wird wenn beim Aufruf der letzte Parameter weggelassen wird. Verwandte:

Die Adressierung von Pavel ist gültig Kommentar , verkette ich _limit und _offset direkt, sodass die Abfrage bereits mit diesen Parametern geplant ist.

_limit und _offset sind integer Parameter, sodass wir einfach %s verwenden können ohne die Gefahr einer SQL-Injection. Möglicherweise möchten Sie vernünftige Werte geltend machen (negative Werte und zu hohe Werte ausschließen), bevor Sie ...

verketten Andere Anmerkungen:
  • Verwenden Sie eine konsistente Namenskonvention. Ich habe allen Parametern und Variablen einen Unterstrich _ vorangestellt , nicht nur einige .

  • Keine Tabellenqualifizierung in EXECUTE verwenden , da es sich nur um eine einzige Tabelle handelt und die EXECUTE hat einen separaten Geltungsbereich.

  • Zur Verdeutlichung habe ich einige Parameter umbenannt. _order_by statt _sort_by; _order_asc_desc statt _order .