PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Dynamiczne ORDER BY i ASC / DESC w funkcji plpgsql

Zrobiłbym to tak:

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

Podstawowa funkcja:użyj formatu format() do bezpiecznego i eleganckiego łączenia ciągu zapytania. Powiązane:

ASC / DESC (lub ASCENDING / DESCENDING ) to stałe słowa kluczowe. Dodałem kontrolę ręczną (IF ... ) i później połącz z prostym %s . To jeden sposób dochodzenia legalnego wkładu. Dla wygody dodałem komunikat o błędzie dla nieoczekiwanych danych wejściowych i domyślny parametr, więc funkcja domyślnie ma wartość ASC jeśli ostatni parametr zostanie pominięty w wywołaniu. Powiązane:

Adresowanie prawidłowe komentarz , łączę _limit i _offset bezpośrednio, więc zapytanie jest już zaplanowane z tymi parametrami.

_limit i _offsetinteger parametry, więc możemy użyć zwykłego %s bez niebezpieczeństwa iniekcji SQL. Możesz chcieć zapewnić rozsądne wartości (wyklucz wartości ujemne i wartości zbyt wysokie) przed połączeniem ...

Inne uwagi:
  • Użyj spójnej konwencji nazewnictwa. Wszystkie parametry i zmienne poprzedziłem podkreśleniem _ , a nie tylko niektóre .

  • Nie używam kwalifikacji tabeli w EXECUTE , ponieważ w grę wchodzi tylko jedna tabela i EXECUTE ma swój odrębny zakres.

  • Zmieniłem nazwy niektórych parametrów, aby wyjaśnić. _order_by zamiast _sort_by; _order_asc_desc zamiast _order .



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zmień język daty PostgreSQL z żądania

  2. Wyodrębnianie wielu poziomów danych xml za pomocą xpath w postgres

  3. Postgres 9.1 vs Mysql 5.6 InnoDB?

  4. Planeta PostgreSQL w galaktyce Ansible

  5. Problem z tygodniową alokacją godzin w Rails i Postgresql