To, o co prosisz, jest niemożliwe . SQL jest językiem ściśle typizowanym. Funkcje PostgreSQL muszą deklarować typ zwracany (RETURNS ..
) w czasie tworzenia .
Ograniczonym sposobem obejścia tego jest użycie funkcji polimorficznych. Jeśli możesz podać typ zwrotu w czasie funkcji zadzwoń . Ale nie wynika to z twojego pytania.
- Refaktoryzuj funkcję PL/pgSQL, aby zwrócić dane wyjściowe różnych zapytań SELECT
możesz zwrócić całkowicie dynamiczny wynik z anonimowymi rekordami. Ale wtedy musisz podać listę definicji kolumn przy każdym wywołaniu. A skąd wiesz o zwróconych kolumnach? Złap 22.
Istnieją różne obejścia, w zależności od tego, czego potrzebujesz lub z czym możesz pracować. Ponieważ wszystkie kolumny danych wydają się mieć ten sam typ danych, sugeruję zwrócenie tablicy :text[]
. Lub możesz zwrócić typ dokumentu, taki jak hstore
lub json
. Powiązane:
-
Dynamiczna alternatywa dla pivota z CASE i GROUP BY
-
Dynamicznie konwertuj klucze hstore na kolumny dla nieznanego zestawu kluczy
Ale prościej może być użycie dwóch wywołań:1:Pozwól Postgresowi zbudować zapytanie. 2:Wykonaj i pobierz zwrócone wiersze.
- Wybieranie wielu wartości max() za pomocą jednej instrukcji SQL
Nie użyłbym funkcji Erica Minikela przedstawionej w Twoim pytaniu w ogóle . Nie jest bezpieczny przed wstrzyknięciem SQL za pomocą złośliwie zniekształconych identyfikatorów. Użyj format()
do tworzenia ciągów zapytań, chyba że używasz przestarzałej wersji starszej niż Postgres 9.1.
Krótsza i czystsza implementacja może wyglądać tak:
CREATE OR REPLACE FUNCTION xtab(_tbl regclass, _row text, _cat text
, _expr text -- still vulnerable to SQL injection!
, _type regtype)
RETURNS text AS
$func$
DECLARE
_cat_list text;
_col_list text;
BEGIN
-- generate categories for xtab param and col definition list
EXECUTE format(
$$SELECT string_agg(quote_literal(x.cat), '), (')
, string_agg(quote_ident (x.cat), %L)
FROM (SELECT DISTINCT %I AS cat FROM %s ORDER BY 1) x$$
, ' ' || _type || ', ', _cat, _tbl)
INTO _cat_list, _col_list;
-- generate query string
RETURN format(
'SELECT * FROM crosstab(
$q$SELECT %I, %I, %s
FROM %I
GROUP BY 1, 2 -- only works if the 3rd column is an aggregate expression
ORDER BY 1, 2$q$
, $c$VALUES (%5$s)$c$
) ct(%1$I text, %6$s %7$s)'
, _row, _cat, _expr -- expr must be an aggregate expression!
, _tbl, _cat_list, _col_list, _type
);
END
$func$ LANGUAGE plpgsql;
To samo wywołanie funkcji, co w oryginalnej wersji. Funkcja crosstab()
jest dostarczany przez dodatkowy moduł tablefunc
który ma być zainstalowany. Podstawy:
- Kwerendy PostgreSQL Crosstab
To bezpiecznie obsługuje nazwy kolumn i tabel. Zwróć uwagę na użycie typów identyfikatorów obiektów regclass
i regtype
. Działa również dla nazw kwalifikowanych według schematu.
- Nazwa tabeli jako parametr funkcji PostgreSQL
Jednak nie jest całkowicie bezpieczny podczas gdy przekazujesz ciąg do wykonania jako wyrażenie (_expr
- cellc
w pierwotnym zapytaniu). Tego rodzaju dane wejściowe są z natury niebezpieczne przed wstrzyknięciem SQL i nigdy nie powinny być udostępniane ogółowi społeczeństwa.
- Wstrzyknięcie SQL w funkcje Postgresa a przygotowane zapytania
Skanuje tabelę tylko raz dla obu list kategorii i powinien być nieco szybszy.
Nadal nie można zwrócić całkowicie dynamicznych typów wierszy, ponieważ jest to absolutnie niemożliwe.