sql >> Databáze >  >> RDS >> PostgreSQL

Dynamické ORDER BY a ASC / DESC ve funkci plpgsql

Udělal bych to takto:

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

Základní funkce:použijte formát format() bezpečně a elegantně zřetězit váš řetězec dotazu. Související:

ASC / DESC (nebo ASCENDING / DESCENDING ) jsou pevná klíčová slova. Přidal jsem ruční kontrolu (IF ... ) a později zřetězit jednoduchým %s . To je jedna způsob, jak uplatnit právní vstup. Pro usnadnění jsem přidal chybovou zprávu pro neočekávaný vstup a výchozí parametr, takže funkce je výchozí ASC pokud je ve volání vynechán poslední parametr. Související:

Adresování Pavel's valid komentář , zřetězím _limit a _offset přímo, takže dotaz je již naplánován s těmito parametry.

_limit a _offset jsou integer parametry, takže můžeme použít obyčejný %s bez nebezpečí SQL injection. Možná budete chtít potvrdit rozumné hodnoty (vyloučit záporné hodnoty a příliš vysoké hodnoty) před zřetězením ...

Další poznámky:
  • Použijte konzistentní konvenci pojmenování. Před všemi parametry a proměnné jsem uvedl podtržítko _ , nejen některé .

  • Nepoužívá se kvalifikace tabulky uvnitř EXECUTE , protože se jedná pouze o jednu tabulku a EXECUTE má svůj samostatný rozsah.

  • Některé parametry jsem pro upřesnění přejmenoval. _order_by místo _sort_by; _order_asc_desc místo _order .



  1. Jak změnit heslo databáze

  2. Konektor Python MySQL – při použití fetchone byl nalezen nepřečtený výsledek

  3. Problém pro vložení pomocí psycopg

  4. Může primární klíč SQL přijmout '0'?