sql >> Databasteknik >  >> RDS >> PostgreSQL

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

Jag skulle göra så här:

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

Kärnfunktion:använd format() för att säkert och elegant sammanfoga din frågesträng. Relaterat:

ASC / DESC (eller ASCENDING / DESCENDING ) är fasta nyckelord. Jag lade till en manuell kontroll (IF ... ) och senare sammanfoga med en enkel %s . Det är ett sätt att hävda juridisk input. För enkelhetens skull lade jag till ett felmeddelande för oväntad inmatning och en parameterstandard, så funktionen är som standard ASC om den sista parametern utelämnas i anropet. Relaterat:

Adresserar Pavel kommentar , jag sammanfogar _limit och _offset direkt, så frågan är redan planerad med dessa parametrar.

_limit och _offset är integer parametrar, så att vi kan använda vanlig %s utan fara för SQL-injektion. Du kanske vill hävda rimliga värden (uteslut negativa värden och värden för höga) innan du sammanfogar ...

Andra anteckningar:
  • Använd en konsekvent namnkonvention. Jag prefixerade alla parametrar och variabler med ett understreck _ , inte bara en del .

  • Använder inte tabellkvalificering i EXECUTE , eftersom det bara är en enda tabell involverad och EXECUTE har sin separata räckvidd.

  • Jag bytte namn på några parametrar för att förtydliga. _order_by istället för _sort_by; _order_asc_desc istället för _order .



  1. Tips och knep med hjälp av revisionsloggning för MariaDB

  2. Databasdesign för skolgångssystem

  3. Django ORM, infoga ingen datumtid som 0 i MySQL

  4. Hur skapar man lagrade procedurer i SQL?