基本的な文

PostgreSQL 8.0.0 文書
前のページ | 巻戻し | 第 35章PL/pgSQL - SQL手続き言語 | 早送り | 次のページ

# 35.6. 基本的な文

本節および次節では、明示的にPL/pgSQLで解釈される、全ての種類の文について説明します。 これらの種類の文として認められないものは全て、SQLコマンドであると仮定され、(その文で使用されるPL/pgSQL変数を全て代入した後で)メインデータベースエンジンに送信され実行されます。 従って、例えば、`INSERT`、`UPDATE`、`DELETE` SQLコマンドは、PL/pgSQL の文とみなすことができます。しかし、ここではこれらについては言及しません。

## 35.6.1. 代入

値を変数、もしくは行/レコードフィールドに代入する場合は以下のように記述します。

    identifier := expression;

上述した通り、このような文中にある式は、メインデータベースエンジンに送信される`SELECT` SQLコマンドによって評価されます。 式は1つの値を生成しなければなりません。

式の結果データ型が変数のデータ型に一致しない場合、または、変数が(`char(20)`のように)特定の大きさ/精度を持つ場合、結果の値は PL/pgSQLインタプリタによって、結果の型の出力関数と変数の型の入力関数を使用して暗黙的に変換されます。 これにより、結果値の文字列形式を入力関数で受け付けることができない場合に、入力関数において実行時エラーが発生する可能性があることに注意してください。

例

    user_id := 20;
    tax := subtotal * 0.06;

## 35.6.2. `SELECT INTO`

複数列を持つ(しかし1行のみの)`SELECT`コマンドの結果は、レコード変数、行型の変数、スカラ変数のリストに代入することができます。 これは、以下によって行われます。

    SELECT INTO target select_expressions FROM ...;

ここで、`target`はレコード変数、行変数、あるいは、単純な変数とレコード/行変数のフィールドをコンマで区切ったリストです。 `select_expressions`とコマンドの残りの部分は通常のSQLと同じです。

これは、`INTO`の対象は新しく作成されるテーブルであるという、PostgreSQLの通常の`SELECT INTO`の実装とは大きく異なります。 PL/pgSQL 関数内部で`SELECT`の結果からテーブルを作成したい場合は、`CREATE TABLE ... AS SELECT`構文を使用してください。

行または変数リストが対象に使用された場合、選択された値は正確に対象の構造に一致しなければなりません。 さもなければ、実行時エラーが発生します。 レコード変数が対象の場合は、自動的に問い合わせ結果の列の行型に自動的に自身を設定します。

`INTO`句以外は、この`SELECT`文は通常の`SELECT` SQLコマンドと同一であり、`SELECT`の全ての機能を使用することができます。

`INTO` 句は `SELECT` 文のほとんど任意の場所に記述することができます。 習慣的には、上に示したように `SELECT` の直後または `FROM` の直前、すなわち `select_expressions` の直前または直後 に記述されます。

問い合わせが行を返さない場合、NULL値が対象に代入されます。 問い合わせが複数の行を返す場合、最初の行が対象に代入され、残りは破棄されます。 ("最初の行"は`ORDER BY`を使用していない限り完全に明確にならないことに注意してください。)

`SELECT INTO` 文の後で特殊な `FOUND` 変数 (項35.6.6を参照) を検査することにより、代入が正しく行なわれたかどうかを、つまり問い合わせによって少なくとも 1 行が返された かどうかを確認できます。

    SELECT INTO myrec * FROM emp WHERE empname = myname;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'employee % not found', myname;
    END IF;

`IS NULL`条件を使用して、レコードもしくは行結果がNULLかどうかを検査することができます。 しかし、他の行が存在し破棄されたかどうかを判断する方法は存在しないことに注意してください。 以下に、行が全く返されなかった場合を扱う例を示します。

    DECLARE
        users_rec RECORD;
    BEGIN
        SELECT INTO users_rec * FROM users WHERE user_id=3;

        IF users_rec.homepage IS NULL THEN
            -- ユーザがhomepageを入力をしなかったので"http://"を返す。
            RETURN 'http://';
        END IF;
    END;

## 35.6.3. 結果を返さない式、もしくは問い合わせの実行

結果を必要としない問い合わせや式の評価を行いたいことがあります(直接得られる結果は必要がなくても、副次的に得られる結果に意味を見出す関数の呼び出しが典型的)。 これを PL/pgSQLで行うには、`PERFORM`文を使用してください。

    PERFORM query;

これは `query` を実行し、その結果を破棄します。 SQL の `SELECT` 文と同じ方法で `query` を記述しますが、最初のキーワード `SELECT` を `PERFORM` に置き換えてください。 PL/pgSQL 変数は通常通り問い合わせ内で置き換えられます。 また、特殊な変数である `FOUND` は問い合わせ結果が 1 行でも生成された場合は真に設定され、生成されない場合は偽に設定されます。。

> 注意: `INTO`句を持たない`SELECT`でこの結果を果たすことができると考えるかもしれませんが、現時点では、これを行う方法は`PERFORM`しかありません。

以下に例を示します。

    PERFORM create_mv('cs_session_page_requests_mv', my_query);

## 35.6.4. 全く何もしない

何もしないプレースホルダ文が有用になることがあります。 例えば、IF/THEN/ELSE 文の一部が空文であることを明示したいときです。 このような目的には、`NULL` 文を使用します。

    NULL;

例えば、次の 2つのコードは同等です。

        BEGIN
            y := x / 0;
        EXCEPTION
            WHEN division_by_zero THEN
                NULL;  -- 誤りを無視する
        END;

        BEGIN
            y := x / 0;
        EXCEPTION
            WHEN division_by_zero THEN  -- 誤りを無視する
        END;

どちらが望ましいと思うかは、好みの問題です。

> 注意: Oracle の PL/SQL では、無記述の文は許されないので `NULL` 文が必須となります。 それに反して PL/pgSQL では、無記述の文が許可されています。

## 35.6.5. 動的コマンドの実行

PL/pgSQL関数の内部で、動的コマンド、つまり実行する度に別のテーブルや別のデータ型を使用するコマンドを行いたいということがよくあるでしょう。 PL/pgSQLが通常行うコマンドの計画のキャッシュはこのような状況では動作しません。 この種の問題を扱うために、以下の`EXECUTE`文が用意されています。

    EXECUTE command-string;

ここで、`command-string`は、実行されるコマンドを持つ(`text`型の)文字列を与える式です。 この文字列はSQLエンジンにそのまま渡されます。

このコマンド文字列上へのPL/pgSQL変数の置換は行われないことには、特に注意してください。 変数の値は、コマンド文字列を作成する時に埋め込まなければなりません。

PL/pgSQL における他の全てのコマンドとは異なり、`EXECUTE` によって実行されるコマンドはセッションの有効期間中一度だけ解釈、保存されるわけではありません。 代わりに、コマンドは文が実行される時に準備されます。 コマンド文字列は、異なるテーブルと列に対する操作を実行できるように、関数内部で動的に作成することができます。

`SELECT` 問い合わせのからの結果は `EXECUTE` によって捨てられます。 また、`SELECT INTO` は `EXECUTE` では現在サポートされません。 したがって、簡単な `EXECUTE` コマンドを使用して、動的に作成された `SELECT` から結果を抜き出す方法はありません。 しかし、その方法は他に 2つあります。 1つは項35.7.4で述べる `FOR-IN-EXECUTE` ループを使用することです。 もう 1つは項35.8.2で述べる `OPEN-FOR-EXECUTE` によるカーソルを使用することです。

動的コマンドを行う時、PL/pgSQL では単一引用符をエスケープしなければなりません。 推奨されるのは、関数本体における固定のテキストをドル引用符で囲む方法です。 (ドル引用符を用いない旧式のコードを保有している場合は、項35.2.1の概要を参照することが、理解しやすいコードへの変換作業の手助けになります。)

作成した問い合わせに挿入すべき動的な値は、それ自身の内部に引用符を含む可能性があるため、特別な処理が必要です。 以下に例を示します (ここでは関数にドル引用符を用いる方法を使用すると仮定しているので、引用符を二重化する必要はありません)。

    EXECUTE 'UPDATE tbl SET '
            || quote_ident(colname)
            || ' = '
            || quote_literal(newvalue)
            || ' WHERE key = '
            || quote_literal(keyvalue);

この例は、`quote_ident(`text`)`と`quote_literal(`text`)`関数の使用方法を示しています。 安全のため、列とテーブルの識別子を含んでいる変数は`quote_ident()`関数を通らなければいけません。 動的に構築されるコマンド内で、リテラル文字列となるべき値を含んでいる変数は`quote_literal()`関数を通らなければいけません。 両方とも、適切な処理を行い、入力されたテキストを単一引用符もしくは二重引用符で括り、特殊文字を全て適切にエスケープして埋め込んだものを返します。

ドル引用符の方法は一定のテキストを囲むときだけ有用だということに注意してください。 上例を次にようにするのは、とても悪い考えです。

    EXECUTE 'UPDATE tbl SET '
            || quote_ident(colname)
            || ' = $$'
            || newvalue
            || '$$ WHERE key = '
            || quote_literal(keyvalue);

なぜなら、`newvalue` の内容がたまたま `$$` を含むときは、途中で次の処理へ移ってしまうからです。 同様の不測事態は、ドル引用符の他の区切り文字を選んだときも起こります。 したがって、テキストの内容が既知でないときは、安全のために `quote_literal` 関数を使用しなければなりません。

動的問い合わせと `EXECUTE` の長大な例は例35-5で見ることができます。 それは新しい関数を定義するために `CREATE FUNCTION` コマンドを用いて実行するものです。

## 35.6.6. 結果ステータスの取得

コマンドの効果を判断するには、いくつか方法があります。 最初の方法は、以下のような形式の`GET DIAGNOSTICS`を使用する方法です。

    GET DIAGNOSTICS variable = item [ , ... ] ;

このコマンドによって、システムステータスインジケータを取り出すことができます。 各`item`は、指定された変数に割り当てられた状態値を識別するためのキーワードです(これは受けとるために正しいデータ型でなければなりません)。 現在使用可能なステータス項目は、`ROW_COUNT`、`RESULT_OID`の2つです。 `ROW_COUNT`は、最後にSQLエンジンに送信されたSQLコマンドによって処理された行数を示します。 `RESULT_OID`は、最も最近のSQLコマンドによって挿入された最後の行のOIDです。 `RESULT_OID`は`INSERT`コマンドの後でのみ有意であることに注意してください。

以下に例を示します。

    GET DIAGNOSTICS integer_var = ROW_COUNT;

2番目のコマンドの効果を判断する方法は、`FOUND`という`boolean`型の特殊な変数をチェックすることです。 PL/pgSQLの各関数内で使用される際、`FOUND`は最初は偽に設定されています。 以下のように、それぞれの文の種類によって設定が変更されます。

- `SELECT INTO`文は、行が返された場合は真、返されなかった場合は偽を`FOUND`に設定します。

- `PERFORM`文は、行が生成(破棄)された場合は真、生成されなかった場合は偽を`FOUND`に設定します。

- `UPDATE`、`INSERT`、および`DELETE`文は、少なくとも1行が影響を受けた場合は真、全く影響を受けなかった場合は偽を`FOUND`に設定します。

- `FETCH`文は、行が返された場合は真、全く返されなかった場合は偽を`FOUND`に設定します。

- `FOR` 文は 1 回以上繰り返しが行なわれた場合は真、行なわれなかった場合は偽を `FOUND` に設定します。 これは 3 種の `FOR` 文全て(整数 `FOR` ループ、レコードセッ ト`FOR` ループ、動的レコードセット `FOR` ループ)に当てはまります。 `FOUND` は `FOR` ループが終了した際、このように設定されます。 つまり、実行ループ内では `FOR` 文によって `FOUND` は変更されません。 ただし、ループ本体内の他種類の文を実行することによって、変更されるかもしれません。

`FOUND` は各々の PL/pgSQL 関数内部のローカル変数です。 故に、`FOUND` に対して行なわれた全ての変更は、現在の関数にのみ影響します。

前のページ | ホーム | 次のページ
式 | 上に戻る | 制御構造