web-dev-qa-db-ja.com

PostgreSQL例外を処理するエレガントな方法?

PostgreSQLでは、例外が発生した場合に空の結果を返すセーフラッピングメカニズムを作成したいと思います。以下を考慮してください。

SELECT * FROM myschema.mytable;

クライアントアプリケーションで安全なラッピングを行うことができます。

try {
    result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
    result = []
}

しかし、SQLでそのようなことを直接行うことはできますか?次のコードを機能させたいのですが、DO $$ ... $$ブロックし、ここで私は迷子になっています。

BEGIN
    SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
    SELECT unnest(ARRAY[]::TEXT[])
END
16
Tregoreg

PL/pgSQLでの例外処理

通常、plpgsqlコードは常に_BEGIN .. END_ブロックにラップされます。それはDOステートメントまたは関数の本体内にあります。ブロックは内部にネストできますが、外部に存在することはできません。これをプレーンSQLと混同しないでください。

BEGINブロックには、例外を処理するためのEXCEPTION句をオプションで含めることができますが、例外をトラップする必要がある関数はかなり高価なので、事前に例外を回避するのが最善です。

詳しくは:

例の例外をavoidする方法

DO ステートメントは何も返すことができません。 function を作成します。これは、テーブルとスキーマ名をパラメーターとして受け取り、必要なものを返します。

_CREATE OR REPLACE FUNCTION f_tbl_value(_tbl text, _schema text = 'public')
  RETURNS TABLE (value text) AS
$func$
DECLARE
   _t regclass := to_regclass(_schema || '.' || _tbl);
BEGIN
   IF _t IS NULL THEN
      value := ''; RETURN NEXT;    -- return single empty string
   ELSE
      RETURN QUERY EXECUTE
      'SELECT value FROM ' || _t;  -- return set of values
   END
$func$ LANGUAGE plpgsql;
_

コール:

_SELECT * FROM f_tbl_value('my_table');
_

または:

_SELECT * FROM f_tbl_value('my_table', 'my_schema');
_
  • 単一のtext列を持つ行のセット、またはテーブルが存在しない場合は空の文字列が必要だと仮定します。

  • また、特定のテーブルが存在する場合、列valueが存在すると仮定します。あなたもそれをテストできますが、あなたはそれを求めませんでした。

  • 両方のパラメーターは大文字と小文字を区別しますtext値です。 SQLステートメントの識別子の処理 とは微妙に異なります。識別子を二重引用符で囲まない場合は、小文字の名前を渡すだけで問題ありません。

  • この例では、スキーマ名のデフォルトは_'public'_です。ニーズに適応します。スキーマを完全に無視して、現在の _search_path_ にデフォルト設定することもできます。

  • to_regclass()はPostgresの新機能です9.4。古いバージョンの場合:

    _IF EXISTS (
       SELECT 1
       FROM   information_schema.tables 
       WHERE  table_schema = _schema
       AND    table_name = _tbl
    );
    _

    これは実際にはより正確です。これは必要なものを正確にテストするからです。その他のオプションと詳細な説明:

  • 動的SQLを使用するときは、常にSQLインジェクションから防御してください! regclassへのキャストがここでのトリックを行います。詳細:

12

列を1つだけ選択している場合、COALESCE()関数がトリックを実行できるはずです。

SELECT COALESCE( value, '{}'::text[] ) FROM myschema.mytable

より多くの行が必要な場合は、タイプを持つ関数を作成する必要があります。

0
Lucas