

 Amazon Redshift は、パッチ 198 以降、新しい Python UDF の作成をサポートしなくなります。既存の Python UDF は、2026 年 6 月 30 日まで引き続き機能します。詳細については、[ブログ記事](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)を参照してください。

# PL/pgSQL の構造
<a name="c_PLpgSQL-structure"></a>

PL/pgSQL は手続き言語であり、他の手続き言語と同じ構造体が多数含まれています。

**Topics**
+ [ブロック](#r_PLpgSQL-block)
+ [変数宣言](#r_PLpgSQL-variable-declaration)
+ [エイリアス宣言](#r_PLpgSQL-alias-declaration)
+ [組み込み変数](#r_PLpgSQL-builtin-variables)
+ [レコード型](#r_PLpgSQL-record-type)

## ブロック
<a name="r_PLpgSQL-block"></a>

PL/pgSQL はブロック構造言語です。プロシージャの完全な本文は、ブロック内で定義されます。ブロックには、変数宣言と PL/pgSQL ステートメントが含まれます。ステートメントは、ネストされたブロックまたはサブブロックである場合もあります。

宣言とステートメントはセミコロンで終了します。ブロックまたはサブブロックの END キーワードの後にセミコロンを続けます。DECLARE キーワードと BEGIN キーワードの後にセミコロンを使用しないでください。

すべてのキーワードと識別子は大文字と小文字を混用して記述できます。識別子は、二重引用符で囲まれていない場合、暗黙で小文字に変換されます。

二重ハイフン (--) は、行末までのコメントを開始します。/\$1 は、次の \$1/ が発生するまでのブロックコメントを開始します。ブロックコメントはネストできません。ただし、二重ハイフンコメントはブロックコメントで囲むことができます。また、二重ハイフンはブロックコメントの区切り記号 /\$1 および \$1/ を隠すことができます。

ブロックのステートメントセクションのいずれのステートメントもサブブロックにすることができます。サブブロックを使用して論理グループを構成したり、変数を小グループのステートメントにローカライズしたりできます。

```
[ <<label>> ]
[ DECLARE
  declarations ]
BEGIN
  statements
END [ label ];
```

ブロックに先行する宣言セクションで宣言された変数は、ブロックが入力されるたびにデフォルト値に初期化されます。つまり、初期化される回数は関数呼び出しごとに 1 回とは限りません。

例を以下に示します。

```
CREATE PROCEDURE update_value() AS $$
DECLARE
  value integer := 20;
BEGIN
  RAISE NOTICE 'Value here is %', value;  -- Value here is 20
  value := 50;
  --
  -- Create a subblock
  --
  DECLARE
    value integer := 80;
  BEGIN
    RAISE NOTICE 'Value here is %', value;  -- Value here is 80
  END;

  RAISE NOTICE 'Value here is %', value;  -- Value here is 50
END;
$$ LANGUAGE plpgsql;
```

EXIT ステートメントで使用するブロックを識別したり、ブロックで宣言する変数の名前を修飾したりするには、ラベルを使用します。

PL/pgSQL でステートメントをグループ分けする BEGIN/END と、トランザクションコントロール用のデータベースコマンドを混同しないでください。PL/pgSQL の BEGIN および END は単にグループ分けするためのものです。トランザクションを開始または終了することはありません。

## 変数宣言
<a name="r_PLpgSQL-variable-declaration"></a>

ループ変数を例外として、ブロック内のすべての変数をブロックの DECLARE セクションで宣言します。変数は任意の有効な Amazon Redshift データ型を使用できます。サポートされているデータ型については、[データ型](c_Supported_data_types.md) を参照してください。

PL/pgSQL 変数は Amazon Redshift でサポートされている任意のデータ型と、さらに `RECORD` および `refcursor` を使用できます。`RECORD` の詳細については、[レコード型](#r_PLpgSQL-record-type) を参照してください。`refcursor` の詳細については、[カーソル](c_PLpgSQL-statements.md#r_PLpgSQL-cursors) を参照してください。

```
DECLARE
name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];
```

変数宣言の例を以下に示します。

```
customerID integer;
numberofitems numeric(6);
link varchar;
onerow RECORD;
```

整数の範囲を反復処理する FOR ループのループ変数は、自動的に整数変数として宣言されます。

DEFAULT 句 (ある場合) は、ブロックの入力時に変数に代入する初期値を指定します。DEFAULT 句がない場合、変数は SQL の NULL 値に初期化されます。CONSTANT オプションは、変数への代入を禁止して、ブロックの存続期間中、変数の値を一定に維持します。NOT NULL を指定すると、NULL 値を代入したときにランタイムエラーが発生します。NOT NULL として宣言されたすべての変数には、NULL 以外のデフォルト値を指定する必要があります。

デフォルト値はブロックを入力するたびに評価されます。例えば、`now()` を `timestamp` 型の変数に代入すると、変数は関数がプリコンパイルされた時刻ではなく、現在の関数呼び出しの時刻になります。

```
quantity INTEGER DEFAULT 32;
url VARCHAR := 'http://mysite.com';
user_id CONSTANT INTEGER := 10;
```

`refcursor` データ型は、ストアドプロシージャ内のカーソル変数のデータ型です。`refcursor` の値はストアドプロシージャ内から返される場合があります。詳細については、「[ストアドプロシージャから結果セットを返す](stored-procedure-result-set.md)」を参照してください

## エイリアス宣言
<a name="r_PLpgSQL-alias-declaration"></a>

ストアドプロシージャの署名から引数名が省略されている場合、その引数のエイリアスを宣言できます。

```
name ALIAS FOR $n;
```

## 組み込み変数
<a name="r_PLpgSQL-builtin-variables"></a>

以下の組み込み変数がサポートされています。
+ FOUND
+ SQLSTATE
+ SQLERRM
+ GET DIAGNOSTICS integer\$1var := ROW\$1COUNT;

FOUND は Boolean 型の特殊な変数です。FOUND は各プロシージャ呼び出しで最初は false に設定されます。FOUND は以下のタイプのステートメントで設定されます。
+ SELECT INTO

  行を返す場合は FOUND を true に設定し、行を返さない場合は false に設定します。
+ UPDATE、INSERT、および DELETE

  少なくとも 1 つの行が影響を受ける場合は FOUND を true に設定し、どの行も影響を受けない場合は false に設定します。
+ FETCH

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

  FOR ステートメントが 1 回以上反復処理を行う場合は FOUND を true に設定し、それ以外の場合は false に設定します。これは FOR ステートメントの 3 つすべてのバリアント (整数 FOR ループ、レコードセット FOR ループ、動的レコードセット FOR ループ) に該当します。

  FOUND は FOR ループの終了時に設定されます。ループのランタイム内では、FOUND は FOR ステートメントによって変更されません。ただし、ループ本体内の他のステートメントの実行によって変更される場合があります。

例を以下に示します。

```
CREATE TABLE employee(empname varchar);
CREATE OR REPLACE PROCEDURE show_found()
AS  $$
DECLARE
  myrec record;
BEGIN
  SELECT INTO myrec * FROM employee WHERE empname = 'John';
  IF NOT FOUND THEN
    RAISE EXCEPTION 'employee John not found';
  END IF;
END;
$$ LANGUAGE plpgsql;
```

例外ハンドラ内では、特殊な変数 SQLSTATE に、発生した例外に対応するエラーコードが含まれます。特殊な変数 SQLERRM には、例外に関連するエラーメッセージが含まれます。これらの変数は、例外ハンドラー外では未定義であり、使用した場合はエラーが表示されます。

例を以下に示します。

```
CREATE OR REPLACE PROCEDURE sqlstate_sqlerrm() AS
$$
BEGIN
  UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith';
  EXECUTE 'select invalid';
  EXCEPTION WHEN OTHERS THEN
  RAISE INFO 'error message SQLERRM %', SQLERRM;
  RAISE INFO 'error message SQLSTATE %', SQLSTATE;
END;
$$ LANGUAGE plpgsql;
```

ROW\$1COUNT が GET DIAGNOSTICS コマンドと一緒に使用されています。これは、SQL エンジンに送信された最後の SQL コマンドで処理された行の数を示します。

例を以下に示します。

```
CREATE OR REPLACE PROCEDURE sp_row_count() AS
$$
DECLARE
  integer_var int;
BEGIN
  INSERT INTO tbl_row_count VALUES(1);
  GET DIAGNOSTICS integer_var := ROW_COUNT;
  RAISE INFO 'rows inserted = %', integer_var;
END;
$$ LANGUAGE plpgsql;
```

## レコード型
<a name="r_PLpgSQL-record-type"></a>

RECORD 型は、実際のデータ型ではなく、単なるプレースホルダです。レコード型の変数は、SELECT または FOR コマンドの実行中に割り当てられた行の実際の行構造を取ります。レコード変数のサブ構造は、値が割り当てられるたびに変わる場合があります。レコード変数が最初に割り当てられるまでは、変数にサブ構造はありません。サブ構造のフィールドにアクセスしようとすると、ランタイムエラーが発生します。

```
name RECORD;
```

例を以下に示します。

```
CREATE TABLE tbl_record(a int, b int);
INSERT INTO tbl_record VALUES(1, 2);
CREATE OR REPLACE PROCEDURE record_example()
LANGUAGE plpgsql
AS $$
DECLARE
  rec RECORD;
BEGIN
  FOR rec IN SELECT a FROM tbl_record
  LOOP
    RAISE INFO 'a = %', rec.a;
  END LOOP;
END;
$$;
```