web-dev-qa-db-ja.com

PostgreSQLでの動的列名の使用

PostgreSSQL 8.3を使用しています。

このクエリを実行したい:

select COALESCE(col_fr,col,'Unknown') from my_table where id = 'abc';

ストーリーのツイストは、列名colum_frを動的に生成する必要があります。 my_tableには、言語ごとに異なる列があります。何かのようなもの:

id   col   col_ja    col_fr

言語の文字列パラメーターを渡すことができるCrystalレポートでこのクエリを使用しています:

select COALESCE(col_||{?parameter},col,'Unknown') from my_table where id = 'abc';

{?language}の値がfrの場合、内部的には次のようなものに変換されます。

select COALESCE(col_||'fr',col,'Unknown') from my_table where id = 'abc';

これは決して機能しません。

動的にするために、select caseを使用したくありません。
別の解決策として、ストアドプロシージャの作成も試みました。

CREATE OR REPLACE FUNCTION get_policy_name (
  id text,
  lang   text,
  def_value text
)
RETURNS SETOF record AS
$body$
DECLARE
   sql text;
BEGIN
    sql := 'SELECT   COALESCE(col_'||quote_ident(lang)||',col,'||quote_literal(def_value)||')FROM my_table WHERE id ='||quote_literal(id);

   RETURN QUERY EXECUTE sql
END;
$body$ LANGUAGE plpgsql;

単一のレコードを返す必要があります。
動作していません。何が欠けていますか? PostgreSSQL 8.3はRETURN QUERY EXECUTEをサポートしていますか?

2
user36935

RETURN QUERY EXECUTEはPostgres 8.4で導入されました。
お使いのバージョンは古すぎるため、現在サポートされていません。 より新しいバージョンにアップグレードします。

また、結果の動的列名を取得するのは非常に困難です。 SQLの原則として、名前を含め、戻り値の型を前もって知りたいと考えています。

列定義リストなしで匿名レコードを返すと、単一のレコードに対してのみ機能します。それ以外の場合は、呼び出しで列定義リストを提供する必要があります。 SOに関する彼の質問の詳細:
複数のフィールドをPL/pgSQLを使用してPostgreSQLのレコードとして返す

ポリモーフィック型を使用してこれを回避する方法は限られています。高度なもの:
さまざまなSELECTクエリの出力を返すようにPL/pgSQL関数をリファクタリングします

ところで、あなたの関数は最近のPL/pgSQLでは次のようになります:

CREATE OR REPLACE FUNCTION get_policy_name (
  _id        int,
  _lang      text,
  _def_value text
) RETURNS TABLE (col text) AS
$func$
BEGIN
   RETURN QUERY EXECUTE
   format('SELECT COALESCE(%I, col, $1)
           FROM my_table WHERE id = $2'
         , 'col_' || _lang)
   USING _def_value, _id;
END
$func$ LANGUAGE plpgsql;

コール:

SELECT col AS col_fr FROM get_policy_name (1, 'fr', 'foo');

ここでは、呼び出しでcolumn aliasを使用して、必要なことを実現しています。動的な列名よりもはるかに簡単...

6