あなたが求めているのは不可能です 。 SQLは厳密に型指定された言語です。 PostgreSQL関数はリターンタイプを宣言する必要があります(RETURNS ..
)作成の時点 。
これを回避する限られた方法は、多形関数を使用することです。関数呼び出しの時間にリターンタイプを指定できる場合 。しかし、それはあなたの質問からは明らかではありません。
- PL / pgSQL関数をリファクタリングして、さまざまなSELECTクエリの出力を返します
できます 匿名レコードで完全に動的な結果を返します。ただし、すべての呼び出しで列定義リストを提供する必要があります。そして、返された列についてどのように知っていますか?キャッチ22。
必要なものや使用できるものに応じて、さまざまな回避策があります。すべてのデータ列が同じデータ型を共有しているように見えるため、配列を返すことをお勧めします :text[]
。または、hstore
のようなドキュメントタイプを返すこともできます またはjson
。関連:
-
CASEおよびGROUPBYを使用したピボットの動的な代替手段
-
hstoreキーを未知のキーセットの列に動的に変換します
ただし、2つの呼び出しを使用する方が簡単な場合があります。1:Postgresにクエリを作成させます。 2:返された行を実行して取得します。
- 単一のSQLステートメントを使用して複数のmax()値を選択する
私はあなたの質問で提示されたEricMinikelの関数を使用しません 。悪意を持って不正な形式の識別子によるSQLインジェクションに対しては安全ではありません。 format()
を使用する Postgres 9.1より古いバージョンを実行していない限り、クエリ文字列を作成します。
短くてクリーンな実装は次のようになります:
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;
元のバージョンと同じ関数呼び出し。関数crosstab()
追加モジュールtablefunc
によって提供されます インストールする必要があります。基本:
- PostgreSQLクロス集計クエリ
これにより、列名とテーブル名が安全に処理されます。オブジェクト識別子タイプregclass
の使用に注意してください およびregtype
。スキーマ修飾名でも機能します。
- PostgreSQL関数パラメータとしてのテーブル名
ただし、完全に安全ではありません 式として実行する文字列を渡す間(_expr
-cellc
元のクエリで)。この種の入力は、SQLインジェクションに対して本質的に安全ではないため、一般に公開しないでください。
- Postgres関数でのSQLインジェクションと準備されたクエリ
テーブルを1回だけスキャンします カテゴリの両方のリストで、少し速くなるはずです。
それでも完全に動的な行タイプを返すことはできません。それは厳密には不可能だからです。