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

Dynamisk ORDER BY og ASC / DESC i en plpgsql-funktion

Jeg ville gøre det sådan her:

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

Kernefunktion:brug format() for sikkert og elegant at sammenkæde din forespørgselsstreng. Relateret:

ASC / DESC (eller ASCENDING / DESCENDING ) er faste nøgleord. Jeg tilføjede en manuel kontrol (IF ... ) og senere sammenkæde med en simpel %s . Det er én måde at hævde juridisk input på. For nemheds skyld tilføjede jeg en fejlmeddelelse for uventet input og en parameterstandard, så funktionen er standard til ASC hvis den sidste parameter udelades i opkaldet. Relateret:

Adressering Pavel kommentar , jeg sammenkæder _limit og _offset direkte, så forespørgslen er allerede planlagt med disse parametre.

_limit og _offset er integer parametre, så vi kan bruge almindelig %s uden fare for SQL-injektion. Du vil måske hævde rimelige værdier (ekskluder negative værdier og værdier for høje), før du sammenkæder ...

Andre bemærkninger:
  • Brug en konsekvent navnekonvention. Jeg præfiksede alle parametre og variable med en understregning _ , ikke kun nogle .

  • Bruger ikke tabelkvalifikation i EXECUTE , da der kun er en enkelt tabel involveret og EXECUTE har sit særskilte anvendelsesområde.

  • Jeg omdøbte nogle parametre for at præcisere. _order_by i stedet for _sort_by; _order_asc_desc i stedet for _order .



  1. Forespørgsel efter 2 tabeller i en enkelt forespørgsel

  2. Zen-vogn:Jeg vil gerne forespørge fra en bestemt kategori dens produktnavn, pris, billede, beskrivelse og attributter

  3. Hvordan kan jeg bruge Entity Framework på en objektgraf forbi en dybde på 2 med MySQL Connector / NET?

  4. 🆕 SQL Server 2022 First Look - Top 5 nye funktioner (Bonus 5 funktioner)