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:
- WSTAW z dynamiczna nazwa tabeli w funkcji wyzwalacza
- Specyfikator formatu dla zmiennych całkowitych w format() dla EXECUTE?
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:
- Opcjonalny argument w PL /pgSQL funkcja
- BŁĄD:parametry wejściowe po jednym z wartością domyślną muszą mieć również wartości domyślne w Postgresie
Adresowanie prawidłowe komentarz
, łączę _limit
i _offset
bezpośrednio, więc zapytanie jest już zaplanowane z tymi parametrami.
_limit
i _offset
są integer
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 ...
-
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 iEXECUTE
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
.