PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

ORDER BY dynamique et ASC/DESC dans une fonction plpgsql

Je le ferais comme ceci :

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

Fonctionnalité principale :utilisez le format format() pour concaténer en toute sécurité et élégance votre chaîne de requête. Connexe :

ASC / DESC (ou ASCENDING / DESCENDING ) sont des mots clés fixes. J'ai ajouté une vérification manuelle (IF ... ) et ensuite concaténer avec un simple %s . C'est un façon d'affirmer l'apport juridique. Pour plus de commodité, j'ai ajouté un message d'erreur pour une entrée inattendue et un paramètre par défaut, de sorte que la fonction par défaut est ASC si le dernier paramètre est omis dans l'appel. Connexe :

Adressage Pavel valide commentaire , je concatène _limit et _offset directement, la requête est donc déjà planifiée avec ces paramètres.

_limit et _offset sont integer paramètres, afin que nous puissions utiliser %s sans risque d'injection SQL. Vous voudrez peut-être affirmer des valeurs raisonnables (exclure les valeurs négatives et les valeurs trop élevées) avant de concaténer ...

Autres remarques :
  • Utilisez une convention de dénomination cohérente. J'ai préfixé tous les paramètres et variables avec un trait de soulignement _ , pas seulement quelques .

  • Ne pas utiliser la qualification de table dans EXECUTE , car il n'y a qu'une seule table impliquée et le EXECUTE a sa portée distincte.

  • J'ai renommé certains paramètres pour clarifier. _order_by au lieu de _sort_by; _order_asc_desc au lieu de _order .