web-dev-qa-db-ja.com

クエリが結果を返さなかったかどうかを確認する簡単な方法はPL / pgSQLにありますか?

私は現在PL/pgSQLで少し実験していて、このようなことをするよりエレガントな方法があるかどうか知りたいです:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;
17
icefex

例外ブロックは、条件をチェックするのではなく、エラーをトラップするためのものです。つまり、コンパイル時に何らかの条件を処理できる場合は、エラーとしてトラップするのではなく、通常のプログラムロジックで解決する必要があります。

PL/PgSQLドキュメントの「トラップエラー」セクション には、そのようなヒントがあります。

ヒント:EXCEPTION句を含むブロックは、EXCEPTION句を含まないブロックに比べて、出入りにかなりの費用がかかります。したがって、必要がない場合はEXCEPTIONを使用しないでください。

例外(悪い)またはIF/THEN/ELSIF(良い)を使用する代わりに、これを1つのクエリに書き換えることができます。

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;

本当に2つのクエリが必要な場合は、特別なFOUND変数を使用して、前のクエリで結果が得られたかどうかをテストできます。

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;

必須RTFM以下のリンク:-)

FOUND変数の説明については this を、IF/THENブロックについては this を参照してください。

21
filiprem

ブール型の特殊変数FOUNDを調べることができます。ドキュメントから:

FOUNDは、各PL/pgSQL関数呼び出し内でfalseから始まります。次の各タイプのステートメントによって設定されます。

SELECT INTOステートメントは、行が割り当てられている場合はFOUNDをtrueに設定し、行が返されない場合はfalseを設定します。

PERFORMステートメントは、1つ以上の行を生成(および破棄)する場合はFOUNDをtrueに設定し、行が生成されない場合はfalseを設定します。

UPDATE、INSERT、およびDELETEステートメントは、少なくとも1つの行が影響を受ける場合はFOUNDをtrueに設定し、影響を受ける行がない場合はfalseを設定します。

FETCHステートメントは、行を返す場合はFOUNDをtrueに設定し、行が返されない場合はfalseを設定します。

MOVEステートメントは、カーソルの再配置に成功した場合はFOUNDをtrueに設定し、それ以外の場合はfalseに設定します。

FORまたはFOREACHステートメントは、1回以上繰り返す場合はFOUNDをtrueに設定し、それ以外の場合はfalseに設定します。ループが終了すると、FOUNDはこのように設定されます。ループの実行内では、FOUNDはループステートメントによって変更されませんが、ループ本体内の他のステートメントの実行によって変更される可能性があります。

RETURN QUERYおよびRETURN QUERY EXECUTEステートメントは、クエリが少なくとも1つの行を返す場合はFOUNDをtrueに設定し、行が返されない場合はfalseを設定します。

他のPL/pgSQLステートメントはFOUNDの状態を変更しません。特に、EXECUTEはGET DIAGNOSTICSの出力を変更しますが、FOUNDは変更しないことに注意してください。

FOUNDは各PL/pgSQL関数内のローカル変数です。これを変更すると、現在の機能にのみ影響します。

14
alexk