修飾式の概要

修飾式を使用すると、複雑な値を簡潔な形式で、値が必要になった箇所で宣言および定義できるため、プログラムが明確になり開発者の生産性も向上します。

修飾式は式要素を結合して、ほぼすべてのタイプの値を作成します。レコード、連想配列、ネストした表および可変配列に最も役立ちます。

修飾式は明示的な型の指定を使用することで修飾項目の型を指定します。この明示的な指定はtypemarkと呼ばれるものです。

修飾式の構造は、次のとおりです。

qualified_expression ::= empty_qualified_expression 
                      | simple_qualified_expression 
                      | aggregate_qualified_expression
typemark ::= type_name
type_name ::= identifier 
              | type_name . identifier
empty_qualified_expression ::= typemark ( )
simple_qualified_expression ::= typemark ( expr )
aggregate_qualified_expression ::= typemark ( aggregate )

aggregate ::= [ positional_choice_list ] [ explicit_choice_list ] [ others_choice ]

positional_choice_list ::= ( expr )+
                          | sequence_iterator_choice

sequence_iterator_choice ::= FOR iterator SEQUENCE => expr

explicit_choice_list ::= named_choice_list 
                       | indexed_choice_list
                       | iterator_choice
                       | index_iterator_choice

named_choice_list ::= identifier => expr [,]+

indexed_choice_list ::= expr => expr [,] +

iterator_choice ::= FOR iterator => expr

index_iterator_choice ::= FOR iterator INDEX expr => expr

others_choice ::= OTHERS => expr

構文およびセマンティクスの詳細は、qualified_expression ::=を参照してください。

空の修飾式

空の修飾式は、typemark ( )という形式です。たとえば、TがtypemarkであるT ( )という式は、T型の宣言で定義された新しい値を提供します。PL/SQLでは、すべての型が値の初期化を定義します。場合によっては、単にNULLです。typemarkに制約が含まれている場合、それらの制約を満たすために修飾式の値が必要であり、ない場合は例外が発生します。

単純な修飾式

単純な修飾式は、typemark ( expr)という形式で、exprは必ずしもスカラー値ではなく単一値を生成する式です。

集計修飾式

集計修飾式は、typemark ( aggregate)という形式です。たとえば、Tが複合型のtypemarkである場合、T(C1, C2, ..., Cn)のようになります。ここで、各CはT型のいくつかの要素を表す選択です。

位置指定選択には、初期化する式exprのみが含まれます。集計に位置指定選択が含まれている場合は、他の選択の前にそれらを表示する必要があります。位置指定選択は、構造化された型と下限ベクトル型でのみ使用できます。

名前指定選択は、N1 | N2 | ... | Nn => exprという形式です。名前に使用できるのは1つのみで、名前Niは構造化された型Tのフィールド名です。名前指定選択は、構造化された型でのみ使用できます。

索引指定選択は、I => exprという形式で、索引Iは数値またはvarchar2式です。索引指定選択は、ベクトル型でのみ使用できます。

イテレータ選択は、F..L =>exprという形式で、FおよびLはそれぞれ数値式です。境界は、forループの境界に使用されるのと同じルールに従います。イテレータ選択はベクトル型でのみ使用でき、varchar2索引型のバインドされていないベクトル型では使用できません。

索引指定選択およびイテレータ選択は、I1 | F2..L2 | .. | In => exprのように交互にすることを含め、自由に組み合せることができます。

その他選択は、OTHERS => exprという形式で、表示される場合は最後に表示される必要があります。その他選択は、構造化型および境界ベクトル型でのみ使用できます。

位置指定選択は、明示的な選択の前に置く必要があり、その他選択が表示される場合はその前に置く必要があります。

交互索引またはイテレータ選択は、I1 | F2..L2 | ... | In => exprという形式で、単一索引およびイテレータ選択のコレクションI1 => expr、F2..L2 => expr、...、In => exprと同じ効果があります。

この例は、同じ結果を持つレコードに値を割り当てる様々な方法を示しています。


DECLARE
  TYPE t_rec IS RECORD (
    id   NUMBER,
    val1 VARCHAR2(10),
    val2 VARCHAR2(10),
    val3 VARCHAR2(10)  );

  l_rec t_rec;
BEGIN
  -- Method 1: Direct assignment to record fields (not using aggregate).
  l_rec.id   := 1;
  l_rec.val1 := 'ONE';
  l_rec.val2 := 'TWO';
  l_rec.val3 := 'THREE';

  -- Method 2 : Using aggregate qualified expression positional association
  l_rec := t_rec(1, 'ONE', 'TWO', 'THREE');
 
  -- Method 3 : Using aggregate qualified expression named association
  l_rec := t_rec(id   => 1, val1 => 'ONE', val2 => 'TWO', val3 => 'THREE');
END;
/

イテレータ選択アソシエーション

イテレータ選択アソシエーションは、イテランドを索引として使用します。

イテランド値ごとに、式が評価されコレクションに追加されます。このとき、イテランド値が索引として使用されます。

繰返しコントロールによって生成される各イテランド値:
  1. 式を評価して、式の値を生成します。
  2. コレクション型に該当する場合、イテランドで指定される索引にまでコレクションを拡張します。
  3. イテランド値で指定される索引でコレクションに式の値を追加します。

例6-8 修飾式でのイテレータ選択アソシエーション

この例では、最初からN個までのフィボナッチ数のベクトルを作成します。

result := vec_t (FOR i IN 1..n => fib(i));

この例では、最初からN個までの偶数のベクトルを作成します。


result := vec_t (FOR i IN 1..n => 2*i);

索引イテレータ選択アソシエーション

索引イテレータ選択アソシエーションは、値式と連動する索引式を実現します。

イテランド値ごとに、索引式と値式が評価されます。その後で、拡張された値が、拡張された索引を使用してコレクションに追加されます。

繰返しコントロールによって生成される各イテランド値:
  1. 式を評価して、式の値を生成します。
  2. 索引式を評価して、索引値を生成します。
  3. コレクション型に該当する場合、索引値で指定される索引にまでコレクションを拡張します。
  4. 索引値で指定される索引でコレクションに式の値を追加します。

例6-9 修飾式での索引イテレータ選択アソシエーション

この例では、Nずつ増分する値でvecのコピーを作成します。


result := vec_t (FOR I,j IN PAIRS OF vec INDEX I => j+n);

この例では、最初からN個までの偶数のベクトルを作成します。


result := vec_t (FOR i IN 2..n BY 2 INDEX i/2 => i);

シーケンス・イテレータ選択アソシエーション

シーケンス・イテレータ選択アソシエーションを使用すると、値のシーケンスをコレクションの末尾に追加できます。どの場合でも、指定する式でイテランドを参照することがあります。

イテランド値ごとに、値式が評価されてコレクションの末尾に追加されます。

繰返しコントロールによって生成される各イテランド値:
  1. 式を評価して、式の値を生成します。
  2. コレクション型に該当する場合、コレクションを1つ拡張します。
  3. コレクションの末尾に式の値を追加します。

例6-10 修飾式でのシーケンス・イテレータ選択アソシエーション

この例では、ベクトルv1と反転されたv2を連結してまとめます。


result := vec_t (FOR v IN VALUES OF v1, 
                          REVERSE VALUES OF v2
                   SEQUENCE => v);

この例では、N以下の素数のベクトルを作成します。


result := vec_t (FOR i IN 1..n WHEN is_prime(i)
                   SEQUENCE => i);

例6-11 修飾式を使用した連想配列型変数への値の代入

この例では、ファンクションを使用してBOOLEANの表の値を表示します。

Live SQL:

この例は、Oracle Live SQLの18c修飾式を使用した連想配列型変数への値の代入で表示および実行できます。

CREATE FUNCTION print_bool (v IN BOOLEAN)
  RETURN VARCHAR2
IS
  v_rtn VARCHAR2(10);
BEGIN
  CASE v
  WHEN TRUE THEN
    v_rtn := 'TRUE';
  WHEN FALSE THEN
    v_rtn := 'FALSE';
  ELSE
    v_rtn := 'NULL';
  END CASE;
  RETURN v_rtn;
END print_bool;
/

変数v_aa1は索引キーと値のペアを使用して初期化されます。


DECLARE
  TYPE t_aa IS TABLE OF BOOLEAN INDEX BY PLS_INTEGER;
  v_aa1 t_aa := t_aa(1=>FALSE,
                     2=>TRUE,
                     3=>NULL);
BEGIN
  DBMS_OUTPUT.PUT_LINE(print_bool(v_aa1(1)));
  DBMS_OUTPUT.PUT_LINE(print_bool(v_aa1(2)));
  DBMS_OUTPUT.PUT_LINE(print_bool(v_aa1(3)));
END;
/

結果:

FALSE
TRUE
NULL

例6-12 修飾式を使用したRECORD型変数への値の代入

この例は、修飾式を使用して割り当てられた値のレコードを示しています。rec.aの値は位置表記を使用して割り当てられ、rec.cの値は名前関連付けを使用し、rec.bは位置と名前関連付けによって定義されていないために他の表記法に該当し値2が割り当てられます。

DECLARE 
  TYPE r IS RECORD(a PLS_INTEGER, b PLS_INTEGER, c NUMBER);  
  rec r;
BEGIN  
  rec := r(1, c => 3.0, OTHERS => 2);  
-- rec contains [ 1, 2, 3.0 ]
END;
/

例6-13 修飾式を使用したVARRAY型への値の代入

この例では、変数配列vecに[ 1, 3, 2, 3 ]が含まれています。

DECLARE 
  TYPE v IS VARRAY(4) OF NUMBER;  
  vec v;
BEGIN 
  vec := v(1, 3 => 2, OTHERS => 3);  
END;
/