To, co požadujete, je nemožné . SQL je striktně typovaný jazyk. Funkce PostgreSQL musí deklarovat návratový typ (RETURNS ..
) v době vytvoření .
Omezený způsob, jak to obejít, je s polymorfními funkcemi. Pokud můžete poskytnout návratový typ v čase funkce zavolejte . Ale to z vaší otázky nevyplývá.
- Refaktorujte funkci PL/pgSQL tak, aby vrátila výstup různých SELECT dotazů
můžete vrátit zcela dynamický výsledek s anonymními záznamy. Ale pak musíte při každém volání poskytnout seznam definic sloupců. A jak víte o vrácených sloupcích? Chytit 22.
Existují různá řešení v závislosti na tom, co potřebujete nebo s čím můžete pracovat. Protože se zdá, že všechny vaše datové sloupce sdílejí stejný datový typ, doporučuji vrátit pole :text[]
. Nebo můžete vrátit typ dokumentu jako hstore
nebo json
. Související:
-
Dynamická alternativa k pivotu s CASE a GROUP BY
-
Dynamicky převádějte klíče hstore na sloupce pro neznámou sadu klíčů
Ale může být jednodušší použít pouze dvě volání:1:Nechte Postgres sestavit dotaz. 2:Proveďte a načtěte vrácené řádky.
- Výběr více hodnot max() pomocí jednoho příkazu SQL
Funkci od Erica Minikela, jak je uvedena ve vaší otázce, bych vůbec nepoužil . Není bezpečný proti vkládání SQL prostřednictvím škodlivě zdeformovaných identifikátorů. Použijte format()
k vytváření řetězců dotazů, pokud nepoužíváte zastaralou verzi starší než Postgres 9.1.
Kratší a čistší implementace by mohla vypadat takto:
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;
Stejné volání funkce jako vaše původní verze. Funkce crosstab()
poskytuje doplňkový modul tablefunc
který se musí nainstalovat. Základy:
- PostgreSQL Crosstab Query
To bezpečně zpracovává názvy sloupců a tabulek. Všimněte si použití typů identifikátorů objektu regclass
a regtype
. Funguje také pro názvy kvalifikované podle schématu.
- Název tabulky jako parametr funkce PostgreSQL
Není to však úplně bezpečné zatímco předáváte řetězec, který má být proveden jako výraz (_expr
- cellc
ve vašem původním dotazu). Tento druh vstupu je ze své podstaty nebezpečný proti SQL injection a nikdy by neměl být vystaven široké veřejnosti.
- Injekce SQL ve funkcích Postgres vs připravené dotazy
Prohledá tabulku pouze jednou pro oba seznamy kategorií a měl by být o něco rychlejší.
Stále nelze vrátit zcela dynamické typy řádků, protože to přísně není možné.