ヘッダーをスキップ
Oracle Database PL/SQL言語リファレンス
11g リリース1(11.1)
E05670-03
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

2 PL/SQL言語の基礎

この章では、PL/SQL言語の次の点について説明します。

キャラクタ・セットおよび字句単位

PL/SQLでは、識別子およびソース・コードに使用されるデータベース・キャラクタ・セット、および各国語データに使用される各国語キャラクタ・セットの2つのキャラクタ・セットがサポートされています。 このトピックの内容は、データベース・キャラクタ・セットにのみ適用されます。 各国語キャラクタ・セットについては、「NCHARおよびNVARCHAR2データ型」を参照してください。

PL/SQLプログラムは、次の文字を使用したテキストとして作成されます。

PL/SQLキーワードは大/小文字が区別されないため、文字列リテラルと文字リテラルの中を除き、小文字の英字は対応する大文字の英字と等価です。

PL/SQLテキストの行には字句単位と呼ばれる文字のグループがあります。

隣接する識別子は、空白またはデリミタで区切る必要があります。 次に例を示します。

SQL> BEGIN
  2    IF x > y THEN high := x; END IF;  -- correct
  3    IF x > y THEN high := x; ENDIF;   -- incorrect
  4  END;
  5  /
END;
   *
ERROR at line 4:
ORA-06550: line 4, column 4:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
if

SQL>

文字列リテラルとコメントの場合を除き、字句単位の中に空白を埋め込むことはできません。 次に例を示します。

SQL> BEGIN
  2    count := count + 1;   -- correct
  3    count : = count + 1;  -- incorrect
  4  END;
  5  /
  count : = count + 1;  -- incorrect
        *
ERROR at line 3:
ORA-06550: line 3, column 9:
PLS-00103: Encountered the symbol ":" when expecting one of the following:
:= . ( @ % ;

SQL>

構造を示すために、改行で行を分けたり、空白またはタブで行にインデントを付けることができます。 次に例を示します。

SQL> DECLARE
  2    x    NUMBER := 10;
  3    y    NUMBER := 5;
  4    max  NUMBER;
  5  BEGIN
  6    IF x>y THEN max:=x;ELSE max:=y;END IF;  -- correct but hard to read
  7
  8    -- Easier to read:
  9
 10    IF x > y THEN
 11      max:=x;
 12    ELSE
 13      max:=y;
 14    END IF;
 15  END;
 16  /

PL/SQL procedure successfully completed.

SQL>

ここでのトピック:

デリミタ

デリミタは、PL/SQLにとって特別な意味を持つ単純記号またはコンパウンド記号です。 表2-1に、PL/SQLのデリミタを示します。

表2-1 PL/SQLのデリミタ

記号 意味

+


加算演算子

%


属性のインジケータ

'

文字列のデリミタ

.

構成要素の選択子

/


除算演算子

(

式またはリストのデリミタ

)

式またはリストのデリミタ

:

ホスト変数のインジケータ

,

項目のセパレータ

*


乗算演算子

"

二重引用符で囲んだ識別子のデリミタ

=


関係演算子

<


関係演算子

>

関係演算子

@


リモート・アクセスのインジケータ

;

文の終了記号

-

減算/否定演算子

:=

代入演算子

=>

結合演算子

||


連結演算子

**


指数演算子

<<


ラベルのデリミタ(開始)

>>

ラベルのデリミタ(終了)

/*


複数行コメントのデリミタ(開始)

*/


複数行コメントのデリミタ(終了)

..

範囲演算子

<>

関係演算子

!=

関係演算子

~=

関係演算子

^=

関係演算子

<=


関係演算子

>=

関係演算子

--

単一行コメントのインジケータ


識別子

識別子を使用して、定数、変数、例外、カーソル、カーソル変数、サブプログラム、パッケージなどのPL/SQLプログラムに名前を付けることができます。

識別子の最小長は1文字、最大長は30文字です。 最初の文字は英字である必要がありますが、2文字目以降は英字、数字、ドル記号($)、アンダースコア(_)およびシャープ記号(#)のいずれでもかまいません。 たとえば、次の識別子を使用できます。

X
t2
phone#
credit_limit
LastName
oracle$number
money$$$tree
SN##
try_again_

前述の文字以外は、識別子に使用できません。 たとえば、次の識別子は使用できません。

mine&yours  -- ampersand (&) is not allowed
debit-amount -- hyphen (-) is not allowed
on/off       -- slash (/) is not allowed
user id      -- space is not allowed

PL/SQLは、識別子の大/小文字を区別しません。 たとえば、PL/SQLは次の識別子を同じものとみなします。

lastname
LastName
LASTNAME

英字かどうかに関係なく、すべての文字が重要となります。 たとえば、PL/SQLは、次の2つの識別子を別のものとして扱います。

lastname
last_name

識別子はあいまいなものではなく、意味のあるものにします。 たとえば、cost_per_thousandは意味が明白ですが、cptは意味があいまいです。

ここでのトピック:

予約語およびキーワード

予約語キーワードには、いずれもPL/SQLに対して特別な意味があります。 予約語とキーワードの違いとして、予約語は識別子として使用できないという点があげられます。 キーワードは識別子として使用できますが、お薦めしません。

予約語を再定義しようとするとコンパイル・エラーが発生します。 次に例を示します。

SQL> DECLARE
  2    end BOOLEAN;
  3  BEGIN
  4    NULL;
  5  END;
  6  /
  end BOOLEAN;
  *
ERROR at line 2:
ORA-06550: line 2, column 3:
PLS-00103: Encountered the symbol "END" when expecting one of the following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
The symbol "begin was inserted before "END" to continue.
ORA-06550: line 5, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the
following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted

SQL>

表D-1に、PL/SQLの予約語を示します。

キーワードもPL/SQLに対して特別な意味がありますが、キーワードは再定義することができます(ただし、推奨されていません)。 表D-2に、PL/SQLのキーワードを示します。

事前定義の識別子

例外INVALID_NUMBERなど、パッケージSTANDARDでグローバルに宣言されている識別子は、再宣言できます。 ただし、事前定義の識別子を再宣言すると、ローカルな宣言がグローバルな宣言をオーバーライドするためエラーが発生しやすくなります。

二重引用符で囲んだ識別子

柔軟性を高めるために、PL/SQLでは識別子を二重引用符で囲むことができます。 通常は、このようにする必要はありませんが、ときには便利な場合もあります。 二重引用符で囲んだ識別子には、空白など、二重引用符を除くすべての印字可能文字を任意に並べて入れることができます。 したがって、次の識別子は有効です。

"X+Y"
"last name"
"on/off switch"
"employee(s)"
"*** header info ***"

二重引用符で囲んだ識別子の最大サイズは、二重引用符を数えずに30字です。 PL/SQLの予約語を二重引用符で囲んだ識別子として使用することもできますが、それは好ましくないプログラミング習慣です。

リテラル

リテラルは、識別子によって表現する必要がない明示的な数値、文字、文字列またはブール値です。 例として、数値リテラル147やブール・リテラルFALSEがあり PL/SQLのデータ型の詳細は、「事前定義のPL/SQLのスカラー・データ型およびサブタイプ」を参照してください。

ここでのトピック:

数値リテラル

算術式では、整数と実数の2種類の数値リテラルを使用できます。 整数リテラルは、小数点を持たず、必要に応じて符号を付けた整数です。 次に例を示します。

030   6   -14   0   +32767

実数リテラルとは、小数点を持ち、必要に応じて符号を付けた整数または小数です。 次に例を示します。

6.6667   0.0   -12.0   3.14159   +8300.00   .5   25.

PL/SQLでは、12.025.などの数字は、整数値がある場合でも実数とみなします。

数字のみで構成される-2147483648から2147483647の範囲の数値リテラルの値は、PLS_INTEGERデータ型です。それ以外の数値リテラルは、NUMBERデータ型です。 数値のみで構成されているリテラル値の後にfまたはdを追加して、それぞれBINARY_FLOATまたはBINARY_TABLEを指定できます。 データ型のプロパティは、「事前定義のPL/SQL数値データ型およびサブタイプ」を参照してください。

数値リテラルはドル記号やカンマを含むことはできませんが、科学表記法で書くことができます。 数字の後にE(またはe)を付けて、必要な場合は符号付き整数を続けます。 次に例を示します。

2E5   1.0E-7   3.14159e0   -1E38   -9.5e-3

xEyは、xに10のy乗を掛けることを意味します。 次の例で示すように、Eの前の数に、Eの後の数の10の累乗を掛けます(二重アスタリスク(**)は指数演算子です)。

5E3 = 5 * 10**3 = 5 * 1000 = 5000

Eの後の数値は、小数点が移動する桁数にも対応しています。 上の例では、暗黙的な小数点が3桁右に移動しました。 次の例では、3桁左に移動します。

5E-3 = 5 * 10**-3 = 5 * 0.001 = 0.005

NUMBERリテラルの絶対値は、1.0E-130から1.0E126(ただし、1.0E126を含まない)の範囲にすることができます。 リテラルは、0の場合もあります。有効範囲外の結果の詳細は、「NUMBERデータ型」を参照してください。

例2-1 NUMBERリテラル

SQL> DECLARE
  2    n NUMBER;
  3  BEGIN
  4    n := -9.999999E-130;
  5    n :=  9.999E125;
  6    n := 10.0E125;
  7  END;
  8  /
  n := 10.0E125;
       *
ERROR at line 6:
ORA-06550: line 6, column 8:
PLS-00569: numeric overflow or underflow
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored

SQL>

例2-2に示すように、実数リテラルには、後ろにfまたはd文字を付けて、BINARY_FLOATまたはBINARY_DOUBLE型を指定できます。

例2-2 BINARY_FLOATおよびBINARY_DOUBLEの使用

SQL> DECLARE
  2    x BINARY_FLOAT := sqrt(2.0f);
  3      -- single-precision floating-point number
  4    y BINARY_DOUBLE := sqrt(2.0d);
  5      -- double-precision floating-point number
  6  BEGIN
  7    NULL;
  8  END;
  9  /

PL/SQL procedure successfully completed.

SQL>

文字リテラル

文字リテラルは引用符(')で囲まれた1文字のことです。 文字リテラルには、PL/SQLキャラクタ・セットのすべての印刷可能文字(英字、数字、空白および特殊記号)を使用できます。 次に例を示します。

'Z'   '%'   '7'   ' '   'z'   '('

文字リテラルの中で、PL/SQLは大/小文字を区別します。 このため、PL/SQLはリテラル'Z''z'を違うものとして扱います。 また文字リテラル'0'から'9'は、整数リテラルと同じではありませんが、暗黙のうちに整数に変換されるため、算術式の中で使用できます。

文字列リテラル

文字値は、識別子によって表現することも、引用符(')で囲まれた0(ゼロ)文字以上の並びである文字列リテラルとして明示的に書くこともできます。 NULL文字列('')を除くすべての文字列リテラルは、CHARデータ型に属します。 次に例を示します。

'Hello, world!'
'XYZ Corporation'
'10-NOV-91'
'He said "Life is like licking honey from a thorn."'
'$1,000,000'

文字列リテラルの中で、PL/SQLは大/小文字を区別します。 たとえば、PL/SQLは次の2つのリテラルを異なるものとして扱います。

'baker'
'Baker'

文字列の中でアポストロフィを表現する場合は、引用符を2つ書きます。これは二重引用符を書く場合とは違う意味を持ちます。

'I''m a string, you''re a string.'

次の表記法を使用して、リテラルに独自のデリミタ文字を定義することもできます。 デリミタ文字には、文字列に含まれていない文字を使用します。これによって、リテラル内の引用符をエスケープする必要がなくなります。

-- q'!...!' notation allows use of single quotes inside literal
string_var := q'!I'm a string, you're a string.!';

デリミタ[、{、<、(を]、}、>、)とペアで使用すると、'INVALID'の前後の引用符を二重にすることなく、SQL文を表す文字列リテラルをサブプログラムに渡すことができます。

func_call(q'[SELECT index_name FROM user_indexes
  WHERE status ='INVALID']');

NCHARリテラルおよびNVARCHAR2リテラルの前には、次の例のように、qではなくnqを付けます。この場合、00E0は文字éを表します。

where_clause := nq'#WHERE COL_VALUE LIKE '%\00E9'#';

NCHARデータ型およびUnicode文字列の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

ブール・リテラル

ブール・リテラルとは、事前定義の値TRUEFALSEおよびNULLのことです。 NULLは、存在しない値、不明な値または適用できない値を示します。 ブール・リテラルは値であり、文字列ではないことに注意してください。 たとえば、TRUEは数値25と同じように1つの値です。

日付および時間リテラル

例2-3に示すように、日時リテラルには、データ型に応じて様々な形式があります。

例2-3 日時リテラルの使用

SQL> DECLARE
  2    d1 DATE      := DATE '1998-12-25';
  3    t1 TIMESTAMP := TIMESTAMP '1997-10-22 13:01:01';
  4
  5    t2 TIMESTAMP WITH TIME ZONE :=
  6       TIMESTAMP '1997-01-31 09:26:56.66 +02:00';
  7
  8    -- Three years and two months
  9    -- For greater precision, use the day-to-second interval
 10
 11    i1 INTERVAL YEAR TO MONTH := INTERVAL '3-2' YEAR TO MONTH;
 12
 13    -- Five days, four hours, three minutes, two and 1/100 seconds
 14
 15     i2 INTERVAL DAY TO SECOND :=
 16       INTERVAL '5 04:03:02.01' DAY TO SECOND;
 17
 18  BEGIN
 19    NULL;
 20  END;
 21  /

PL/SQL procedure successfully completed.

SQL>

参照:

  • 日付/時刻型の構文は、『Oracle Database SQL言語リファレンス』を参照してください。

  • 日付/時刻算術の例は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。


コメント

PL/SQLコンパイラは、コメントを無視します。 プログラムにコメントを付け加えると、わかりやすくなり理解に役立ちます。 一般に、コメントは各コード・セグメントの目的や使用方法を説明するために使用します。 また、廃止されたコード部分や作成途中のコード部分をコメントに入れて無効化することもできます。

ここでのトピック:


参照:

コメント

単一行コメント

単一行コメントは、--で始まります。 例2-4に示すように、行の中の任意の場所に置くことができ、その行の終わりまで続きます。

例2-4 単一行コメント

SQL> DECLARE
  2    howmany     NUMBER;
  3    num_tables  NUMBER;
  4  BEGIN
  5    -- Begin processing
  6    SELECT COUNT(*) INTO howmany
  7      FROM USER_OBJECTS
  8        WHERE OBJECT_TYPE = 'TABLE'; -- Check number of tables
  9     num_tables := howmany;          -- Compute some other value
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL>

プログラムのテストまたはデバッグ中に、コード内の1行をコメントにすることによって無効にできます。 次に例を示します。

-- DELETE FROM employees WHERE comm_pct IS NULL

複数行コメント

例2-5に示すように、複数行コメントは、/*で始まって*/で終わり、複数行にまたがることができます。 複数行コメントのデリミタを使用すると、コードの一部分をコメントにできます。

例2-5 複数行コメント

SQL> DECLARE
  2     some_condition  BOOLEAN;
  3     pi              NUMBER := 3.1415926;
  4     radius          NUMBER := 15;
  5     area            NUMBER;
  6  BEGIN
  7    /* Perform some simple tests and assignments */
  8    IF 2 + 2 = 4 THEN
  9      some_condition := TRUE;
 10      /* We expect this THEN to always be performed */
 11    END IF;
 12    /* The following line computes the area of a circle using pi,
 13    which is the ratio between the circumference and diameter.
 14    After the area is computed, the result is displayed. */
 15    area := pi * radius**2;
 16    DBMS_OUTPUT.PUT_LINE('The area is: ' || TO_CHAR(area));
 17  END;
 18  /
The area is: 706.858335

PL/SQL procedure successfully completed.

SQL>

宣言

プログラムは、変数と定数に値を格納します。 プログラムの実行中に、変数の値を変更できますが、定数の値は変更できません。

変数および定数は、任意のPL/SQLブロック、サブプログラムまたはパッケージの宣言部で宣言できます。 宣言によって、値の記憶域を割り当て、データ型を指定し、値を参照できるように格納場所の名前を決めます。

ここでのトピック:

変数

例2-6では、DATE型の変数、(初期値0が代入される)SMALLINT型の変数および3つのREAL型の変数を宣言しています。 代入演算子の後に続く式は複雑なものでもかまいません。また、area変数の宣言の場合と同様に、事前に初期化されている変数を参照することもできます。

変数は、ブロックまたはサブプログラムに入るたびに初期化されます。 デフォルトでは、変数はNULLに初期化されます。

例2-6 変数の宣言

SQL> DECLARE
  2    birthday   DATE;
  3    emp_count  SMALLINT := 0;
  4    pi         REAL := 3.14159;
  5    radius     REAL := 1;
  6    area       REAL := pi * radius**2;
  7  BEGIN
  8    NULL;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL>

定数

定数を宣言するには、型指定子の前にキーワードCONSTANTが必要です。 次の宣言では、REAL型の定数の名前を決め、定数に変更不可能な値5000を代入しています。 定数は、宣言の中で初期化する必要があります。 定数は、ブロックまたはサブプログラムに入るたびに初期化されます。

例2-7 定数の宣言

SQL> DECLARE
  2    credit_limit      CONSTANT REAL    := 5000.00;
  3    max_days_in_year  CONSTANT INTEGER := 366;
  4    urban_legend      CONSTANT BOOLEAN := FALSE;
  5  BEGIN
  6    NULL;
  7  END;
  8  /

PL/SQL procedure successfully completed.

SQL>

DEFAULTの使用

変数の初期化には、代入演算子のかわりにキーワードDEFAULTも使用できます。 DEFAULTを使用して、サブプログラム・パラメータ、カーソル・パラメータおよびユーザー定義レコードのフィールドを初期化することもできます。

標準的な値を持つ変数には、DEFAULTを使用します。 特殊な値を持つ変数(カウンタやアキュムレータ)には、代入演算子を使用します。

例2-8 DEFAULTキーワードを使用した変数へのデフォルト値の代入

SQL> DECLARE
  2    blood_type CHAR DEFAULT 'O';         -- Same as blood_type CHAR := 'O';
  3
  4    hours_worked    INTEGER DEFAULT 40;  -- Typical value
  5    employee_count  INTEGER := 0;        -- No typical value
  6
  7  BEGIN
  8    NULL;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL>

NOT NULLの使用

宣言でNOT NULL制約を指定し、変数にNULL値を代入できないようにすることができます。 変数はデフォルトでNULLに初期化されるため、NOT NULLを指定する宣言でもデフォルト値を指定する必要があります。

PL/SQLサブタイプNATURALNPOSITIVENおよびSIMPLE_INTEGERは、NOT NULLと同様に事前定義されています。 これらのサブタイプのいずれかの変数を宣言する場合、NOT NULL制約は省略できますが、デフォルト値は指定する必要があります。

例2-9 NOT NULL制約が指定された変数の宣言

SQL> DECLARE
  2    acct_id INTEGER(4) NOT NULL := 9999;
  3    a NATURALN                  := 9999;
  4    b POSITIVEN                 := 9999;
  5    c SIMPLE_INTEGER            := 9999;
  6  BEGIN
  7    NULL;
  8  END;
  9  /

PL/SQL procedure successfully completed.

SQL>

%TYPE属性の使用

%TYPE属性を使用すると、事前に宣言されている変数、フィールド、レコード、ネストした表またはデータベース列と同じデータ型の定数、変数、フィールドまたはパラメータを宣言できます。 参照先項目が変更されると、宣言は自動的に更新されます。 これによって、たとえば、VARCHAR2列を長くする場合にコードを変更する必要がなくなります。

%TYPEを使用して宣言された項目(参照元項目)は、常に、参照先項目のデータ型を継承します。 参照元項目は、参照先項目がデータベース列ではない場合にのみ、制約を継承します。 参照元項目は、データベース列ではなく、NOT NULL制約を持たない場合にのみ、デフォルト値を継承します。

例2-10では、変数debitは、変数creditのデータ型を継承しています。 変数upper_namelower_nameおよびinit_nameは、変数nameのデータ型およびデフォルト値を継承しています。

例2-10 %TYPEを使用したその他の変数の型の変数の宣言

SQL> DECLARE
  2    credit  PLS_INTEGER RANGE 1000..25000;
  3    debit   credit%TYPE;  -- inherits data type
  4
  5    name        VARCHAR2(20) := 'JoHn SmItH';
  6    upper_name  name%TYPE;  -- inherits data type and default value
  7    lower_name  name%TYPE;  -- inherits data type and default value
  8    init_name   name%TYPE;  -- inherits data type and default value
  9  BEGIN
 10    DBMS_OUTPUT.PUT_LINE ('name: ' || name);
 11    DBMS_OUTPUT.PUT_LINE ('upper_name: ' || UPPER(name));
 12    DBMS_OUTPUT.PUT_LINE ('lower_name: ' || LOWER(name));
 13    DBMS_OUTPUT.PUT_LINE ('init_name:  ' || INITCAP(name));
 14  END;
 15  /
name: JoHn SmItH
upper_name: JOHN SMITH
lower_name: john smith
init_name:  John Smith

PL/SQL procedure successfully completed.

SQL>

例2-10の変数nameNOT NULL制約を追加し、この変数を参照する別の変数を宣言する場合は、例2-11に示すように、新しい項目にデフォルト値を指定する必要があります。

例2-11 NOT NULL参照型での%TYPEの不適切な使用

SQL> DECLARE
  2    name    VARCHAR2(20) NOT NULL := 'JoHn SmItH';
  3    same_name   name%TYPE;
  4  BEGIN
  5    NULL;
  6  END;
  7  /
  same_name   name%TYPE;
              *
ERROR at line 3:
ORA-06550: line 3, column 15:
PLS-00218: a variable declared NOT NULL must have an initialization assignment

SQL>

例2-12では、変数upper_namelower_nameおよびinit_nameは、変数nameのデータ型およびNOT NULL制約を継承していますが、デフォルト値は継承していません。 例2-11に示すエラーを回避するには、これらに独自のデフォルト値を代入します。

例2-12 NOT NULL参照型での%TYPEの適切な使用

SQL> DECLARE
  2    name        VARCHAR2(20) NOT NULL := 'JoHn SmItH';
  3    upper_name  name%TYPE := UPPER(name);
  4    lower_name  name%TYPE := LOWER(name);
  5    init_name   name%TYPE := INITCAP(name);
  6  BEGIN
  7    DBMS_OUTPUT.PUT_LINE('name: ' || name);
  8    DBMS_OUTPUT.PUT_LINE('upper_name: ' || upper_name);
  9    DBMS_OUTPUT.PUT_LINE('lower_name: ' || lower_name);
 10    DBMS_OUTPUT.PUT_LINE('init_name:  ' || init_name);
 11  END;
 12  /
name: JoHn SmItH
upper_name: JOHN SMITH
lower_name: john smith
init_name:  John Smith

PL/SQL procedure successfully completed.

SQL>

%TYPE属性は、データベース列を参照する変数を宣言する場合に特に便利です。 table_name.column_name.%TYPEを使用してデータ項目を宣言する場合、参照されるデータ型または属性(精度、位取りおよび長さなど)を知っておく必要はありません。また、これらが変更された場合でも、コードを更新する必要はありません。

例2-13では、参照元項目が、列制約またはデフォルト値をデータベース列から継承していないことを示しています。

例2-13 %TYPEを使用した表の列の型の変数の宣言

SQL> CREATE TABLE employees_temp (
  2    empid  NUMBER(6) NOT NULL PRIMARY KEY,
  3    deptid NUMBER(6) CONSTRAINT c_employees_temp_deptid
  4      CHECK (deptid BETWEEN 100 AND 200),
  5    deptname VARCHAR2(30) DEFAULT 'Sales'
  6  );

Table created.

SQL>
SQL> DECLARE
  2    v_empid    employees_temp.empid%TYPE;
  3    v_deptid   employees_temp.deptid%TYPE;
  4    v_deptname employees_temp.deptname%TYPE;
  5  BEGIN
  6    v_empid := NULL;  -- Null constraint not inherited
  7    v_deptid := 50;   -- Check constraint not inherited
  8    DBMS_OUTPUT.PUT_LINE
  9      ('v_deptname: ' || v_deptname);  -- Default value not inherited
 10  END;
 11  /
v_deptname:

PL/SQL procedure successfully completed.

SQL>

参照:


%ROWTYPE属性の使用

%ROWTYPE属性を使用すると、表またはビュー内の行を表すレコード型を宣言できます。 参照される表またはビュー内の各列に対して、同じ名前およびデータ型のフィールドがレコードにあります。 レコード内のフィールドを参照するには、record_name.field_nameを使用します。 例2-14に示すように、このレコードのフィールドは、対応する列の制約またはデフォルト値を継承しません。

参照先項目の表またはビューが変更されると、宣言は自動的に更新されます。 列が表またはビューに追加されたり、表またはビューから削除された場合などに、コードを変更する必要はありません。

例2-14 %ROWTYPEを使用した、表の行を表すレコードの宣言

SQL> CREATE TABLE employees_temp (
  2    empid  NUMBER(6) NOT NULL PRIMARY KEY,
  3    deptid NUMBER(6) CONSTRAINT c_employees_temp_deptid
  4      CHECK (deptid BETWEEN 100 AND 200),
  5    deptname VARCHAR2(30) DEFAULT 'Sales'
  6  );

Table created.

SQL>
SQL> DECLARE
  2    emprec  employees_temp%ROWTYPE;
  3  BEGIN
  4    emprec.empid := NULL;  -- Null constraint not inherited
  5    emprec.deptid := 50;   -- Check constraint not inherited
  6    DBMS_OUTPUT.PUT_LINE
  7      ('emprec.deptname: ' || emprec.deptname);
  8        -- Default value not inherited
  9  END;
 10  /
emprec.deptname:

PL/SQL procedure successfully completed.

SQL>

参照:

例3-15

例2-14のレコードemprecには、表employees_tempのすべての列に対するフィールドがあります。 例2-15のレコードdept_recには、表departmentsの列のサブセットに対する列があります。

例2-15 表の列のサブセットを表すレコードの宣言

SQL> DECLARE
  2    CURSOR c1 IS
  3      SELECT department_id, department_name
  4        FROM departments;
  5
  6    dept_rec c1%ROWTYPE;  -- includes subset of columns in table
  7
  8  BEGIN
  9    NULL;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL>

例2-15のレコードjoin_recには、2つの表employeesおよびdepartmentsからの列があります。

例2-16 結合からの列を表すレコードの宣言

SQL> DECLARE
  2    CURSOR c2 IS
  3      SELECT employee_id, email, employees.manager_id, location_id
  4        FROM employees, departments
  5          WHERE employees.department_id = departments.department_id;
  6
  7     join_rec  c2%ROWTYPE;  -- includes columns from two tables
  8
  9  BEGIN
 10    NULL;
 11  END;
 12  /

PL/SQL procedure successfully completed.

SQL>

ここでのトピック:

集計代入

%ROWTYPE宣言に初期化句を含めることはできませんが、レコード中のすべてのフィールドに一度に値を代入する方法が2つあります。

  • レコードの宣言で同じ表またはカーソルが参照されている場合は、例2-17に示すように、あるレコードを別のレコードに代入できます。

  • SELECT文またはFETCH文を使用すると、レコードに列値のリストを代入できます。

    列名の順番は、参照される表またはビューを作成したCREATE TABLE文またはCREATE VIEW文で定義された順番である必要があります。 レコード型のコンストラクタが存在しない場合は、代入文を使用して列の値のリストをレコードに代入できません。

例2-17 あるレコードの別のレコードへの正しい代入および間違った代入

SQL> DECLARE
  2    dept_rec1  departments%ROWTYPE;
  3    dept_rec2  departments%ROWTYPE;
  4
  5    CURSOR c1 IS SELECT department_id, location_id
  6      FROM departments;
  7
  8    dept_rec3 c1%ROWTYPE;
  9    dept_rec4 c1%ROWTYPE;
 10
 11  BEGIN
 12    dept_rec1 := dept_rec2;  -- declarations refer to same table
 13    dept_rec3 := dept_rec4;  -- declarations refer to same cursor
 14    dept_rec2 := dept_rec3;
 15  END;
 16  /
  dept_rec2 := dept_rec3;
               *
ERROR at line 14:
ORA-06550: line 14, column 16:
PLS-00382: expression is of wrong type
ORA-06550: line 14, column 3:
PL/SQL: Statement ignored

SQL>

例2-18では、SELECT INTO文を使用して、レコードに列値のリストを代入しています。

例2-18 SELECT INTOを使用した集計代入

SQL> DECLARE
  2    dept_rec departments%ROWTYPE;
  3  BEGIN
  4    SELECT * INTO dept_rec
  5      FROM departments
  6        WHERE department_id = 30
  7          AND ROWNUM < 2;
  8  END;
  9  /

PL/SQL procedure successfully completed.

SQL>

エイリアシングの使用

%ROWTYPEに関連付けられたカーソルからフェッチされた選択リストは、単純名を持つ必要があります。また、選択項目が式の場合は、例2-19complete_nameのように別名を持つ必要があります。

例2-19 %ROWTYPEに関連付けられた式の別名の使用

SQL> BEGIN
  2    FOR item IN
  3      (SELECT (first_name || ' ' || last_name) complete_name
  4        FROM employees
  5           WHERE ROWNUM < 11
  6      ) LOOP
  7        DBMS_OUTPUT.PUT_LINE
  8          ('Employee name: ' || item.complete_name);
  9      END LOOP;
 10  END;
 11  /
Employee name: Ellen Abel
Employee name: Sundar Ande
Employee name: Mozhe Atkinson
Employee name: David Austin
Employee name: Hermann Baer
Employee name: Shelli Baida
Employee name: Amit Banda
Employee name: Elizabeth Bates
Employee name: Sarah Bell
Employee name: David Bernstein

PL/SQL procedure successfully completed.

SQL>

宣言の制限

PL/SQLでは前方参照ができません。 宣言文などの他の文で変数または定数を参照するときは、事前に宣言する必要があります。

PL/SQLではサブプログラムの前方宣言が可能です。 詳細は、「相互に起動し合うネストしたサブプログラムの作成」を参照してください。

言語によっては、同一のデータ型の複数の変数の並びを一度に宣言できます。 ただし、PL/SQLではそれができません。 各変数を別々に宣言する必要があります。 領域を節約するために、1行に複数の宣言を含めることができます。 次に例を示します。

SQL> DECLARE
  2    i, j, k, l SMALLINT;
  3  BEGIN
  4    NULL;
  5  END;
  6  /
  i, j, k, l SMALLINT;
   *
ERROR at line 2:
ORA-06550: line 2, column 4:
PLS-00103: Encountered the symbol "," when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table long double ref
char time timestamp interval date binary national character
nchar
ORA-06550: line 2, column 14:
PLS-00103: Encountered the symbol "SMALLINT" when expecting one of the
following:
. ( ) , * @ % & = - + < / > at in is mod remainder not rem =>
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between ||
ORA-06550: line 5, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the
following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted


SQL> DECLARE
  2    i SMALLINT; j SMALLINT; k SMALLINT; l SMALLINT;
  3  BEGIN
  4    NULL;
  5  END;
  6  /

PL/SQL procedure successfully completed.

SQL>

ネーミング規則

PL/SQLの定数、変数、カーソル、カーソル変数、例外、プロシージャ、ファンクション、パッケージには、同じネーミング規則が適用されます。 名前には単純名、修飾名、リモート名または修飾リモート名があります。 次に例を示します。

ここでのトピック:

有効範囲

同じ有効範囲内では、宣言されたすべての識別子が一意である必要があります。 データ型が異なる場合でも、変数とパラメータは同じ名前を共有できません。 例2-20に示すように、重複する識別子が参照された場合は、エラーが発生します。

例2-20 同じ有効範囲での重複する識別子

SQL> DECLARE
  2    id  BOOLEAN;
  3    id  VARCHAR2(5);  -- duplicate identifier
  4  BEGIN
  5    id := FALSE;
  6  END;
  7  /
  id := FALSE;
  *
ERROR at line 5:
ORA-06550: line 5, column 3:
PLS-00371: at most one declaration for 'ID' is permitted
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored

SQL>

識別子に適用される有効範囲規則については、「PL/SQLの識別子の有効範囲と可視性」を参照してください。

大/小文字の区別

例2-21に示すように、定数、変数およびパラメータの名前では、すべての識別子と同様に大/小文字が区別されません。

例2-21 識別子の大/小文字の区別なし

SQL> DECLARE
  2     zip_code INTEGER;
  3     Zip_Code INTEGER;
  4  BEGIN
  5    zip_code := 90120;
  6  END;
  7  /
  zip_code := 90120;
  *
ERROR at line 5:
ORA-06550: line 5, column 3:
PLS-00371: at most one declaration for 'ZIP_CODE' is permitted
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored

SQL>

名前解決

あいまいなSQL文では、データベース列の名前はローカル変数名および仮パラメータ名より優先されます。 たとえば、同じ名前の変数と列が1つのWHERE句で使用された場合、SQLは両方とも列を参照するとみなします。


注意:

例2-22に示すように、変数名が列名として解釈されると、データが誤って削除されることがあります。 例2-22には、このエラーを回避する2つの方法も示されています。

例2-22 名前解決でのブロック・ラベルの使用

SQL> CREATE TABLE employees2 AS
  2    SELECT last_name FROM employees;

Table created.

SQL>
SQL> -- Deletes everyone, because both LAST_NAMEs refer to the column:
SQL>
SQL> BEGIN
  2    DELETE FROM employees2
  3      WHERE last_name = last_name;
  4    DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
  5  END;
  6  /
Deleted 107 rows.

PL/SQL procedure successfully completed.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> -- Avoid error by giving column and variable different names:
SQL>
SQL> DECLARE
  2    last_name    VARCHAR2(10) := 'King';
  3    v_last_name  VARCHAR2(10) := 'King';
  4  BEGIN
  5    DELETE FROM employees2
  6      WHERE last_name = v_last_name;
  7    DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
  8  END;
  9  /
Deleted 2 rows.

PL/SQL procedure successfully completed.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> -- Avoid error by qualifying variable with block name:
SQL>
SQL> <<main>> -- Label block for future reference
  2  DECLARE
  3    last_name    VARCHAR2(10) := 'King';
  4    v_last_name  VARCHAR2(10) := 'King';
  5  BEGIN
  6    DELETE FROM employees2
  7      WHERE last_name = main.last_name;
  8    DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
  9  END;
 10  /
Deleted 2 rows.

PL/SQL procedure successfully completed.

SQL> ROLLBACK;

Rollback complete.

SQL>

例2-23に示すように、ローカル変数と仮パラメータへの参照を、サブプログラム名を使用して修飾できます。

例2-23 名前解決でのサブプログラムの使用

SQL> DECLARE
  2    FUNCTION dept_name (department_id IN NUMBER)
  3      RETURN departments.department_name%TYPE
  4    IS
  5      department_name  departments.department_name%TYPE;
  6    BEGIN
  7      SELECT department_name INTO dept_name.department_name
  8        --   ^column              ^local variable
  9        FROM departments
 10          WHERE department_id = dept_name.department_id;
 11          --    ^column         ^formal parameter
 12      RETURN department_name;
 13    END;
 14  BEGIN
 15    FOR item IN (SELECT department_id FROM departments)
 16    LOOP
 17      DBMS_OUTPUT.PUT_LINE
 18        ('Department: ' || dept_name(item.department_id));
 19    END LOOP;
 20  END;
 21  /
Department: Administration
Department: Marketing
Department: Purchasing
Department: Human Resources
Department: Shipping
Department: IT
Department: Public Relations
Department: Sales
Department: Executive
Department: Finance
Department: Accounting
Department: Treasury
Department: Corporate Tax
Department: Control And Credit
Department: Shareholder Services
Department: Benefits
Department: Manufacturing
Department: Construction
Department: Contracting
Department: Operations
Department: IT Support
Department: NOC
Department: IT Helpdesk
Department: Government Sales
Department: Retail Sales
Department: Recruiting
Department: Payroll

PL/SQL procedure successfully completed.

SQL>

参照:

名前解決の詳細は、付録B「PL/SQLでの識別子名の解決」を参照してください。

シノニム

SQL文CREATE SYNONYMを使用してシノニムを作成し、リモート・スキーマ・オブジェクトに関する位置の透過性を提供できます。 PL/SQLのサブプログラムまたはパッケージ内で宣言された項目に対してシノニムは作成できません。


参照:

SQLのCREATE SYNONYM文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

PL/SQLの識別子の有効範囲と可視性

識別子に対する参照は、その有効範囲と可視性に従って解決されます。 識別子の有効範囲とは、その識別子の参照が可能な、PL/SQLユニットの領域です。 識別子の可視性とは、修飾なしでその識別子の参照が可能な、PL/SQLユニットの領域です。

あるPL/SQLユニットで宣言された識別子は、そのユニットに対してはローカルであり、そのサブユニットに対してはグローバルです。 サブユニットでグローバル識別子が再宣言されると、そのサブユニット内では両方の識別子が有効範囲内にあることになりますが、ローカル識別子のみが表示されます。 グローバル識別子を参照するには、サブユニットでグローバル識別子を修飾する必要があります。

同じPL/SQLユニットで識別子を2回宣言することはできませんが、同じ識別子を2つの異なるユニットで宣言することはできます。 識別子が表す2つの項目は区別され、一方を変更しても他方には影響がありません。

PL/SQLユニットは、あるユニットから同じレベルの他のユニットで宣言されている識別子への参照はできません。そのような識別子は、そのブロックに対してローカルでもグローバルでもないためです。

例2-24に、いくつかのグローバル識別子とローカル識別子の有効範囲と可視性を示します。 グローバル識別子aは、最初のブロックで再宣言されています。

例2-24 識別子の有効範囲と可視性

SQL> DECLARE
  2    a CHAR;  -- Scope of a (CHAR) begins
  3    b REAL;  -- Scope of b begins
  4  BEGIN
  5    -- Visible: a (CHAR), b
  6
  7    DECLARE
  8      a INTEGER;  -- Scope of a (INTEGER) begins
  9      c REAL;     -- Scope of c begins
 10    BEGIN
 11      -- Visible: a (INTEGER), b, c
 12      NULL;
 13    END;          -- Scopes of a (INTEGER) and c end
 14
 15    DECLARE
 16      d REAL;     -- Scope of d begins
 17    BEGIN
 18      -- Visible: a (CHAR), b, d
 19      NULL;
 20    END;          -- Scope of d ends
 21
 22    -- Visible: a (CHAR), b
 23  END;            -- Scopes of a (CHAR) and b end
 24  /

PL/SQL procedure successfully completed.

SQL>

例2-25では、変数birthdateをラベル付きのブロックouterで宣言し、サブブロックで再宣言した後、ブロック・ラベルで名前を修飾することによってサブブロック内で参照しています。

例2-25 ブロック・ラベルによる、再宣言されたグローバル識別子の修飾

SQL> <<outer>>
  2  DECLARE
  3    birthdate DATE := '09-AUG-70';
  4  BEGIN
  5    DECLARE
  6      birthdate DATE;
  7    BEGIN
  8      birthdate := '29-SEP-70';
  9
 10      IF birthdate = outer.birthdate THEN
 11        DBMS_OUTPUT.PUT_LINE ('Same Birthday');
 12      ELSE
 13        DBMS_OUTPUT.PUT_LINE ('Different Birthday');
 14      END IF;
 15    END;
 16  END;
 17  /
Different Birthday

PL/SQL procedure successfully completed.

SQL>

例2-26では、変数ratingをプロシージャcheck_creditで宣言し、プロシージャ内のファンクションで再宣言した後、プロシージャ名で名前を修飾することによってファンクション内で参照しています。 (SQLの組込みファンクションTO_CHARは、引数に相当する文字を戻します。 TO_CHARの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。)

例2-26 サブプログラム名による識別子の修飾

SQL> CREATE OR REPLACE PROCEDURE check_credit (limit NUMBER) AS
  2    rating NUMBER := 3;
  3
  4    FUNCTION check_rating RETURN BOOLEAN IS
  5      rating  NUMBER := 1;
  6      over_limit  BOOLEAN;
  7    BEGIN
  8      IF check_credit.rating <= limit THEN
  9        over_limit := FALSE;
 10      ELSE
 11        over_limit := TRUE;
 12        rating := limit;
 13      END IF;
 14      RETURN over_limit;
 15    END check_rating;
 16  BEGIN
 17    IF check_rating THEN
 18      DBMS_OUTPUT.PUT_LINE
 19        ('Credit rating over limit (' || TO_CHAR(limit) || ').  '
 20        || 'Rating: ' || TO_CHAR(rating));
 21      ELSE
 22        DBMS_OUTPUT.PUT_LINE
 23          ('Credit rating OK.  ' || 'Rating: ' || TO_CHAR(rating));
 24     END IF;
 25  END;
 26  /

Procedure created.

SQL> BEGIN
  2    check_credit(1);
  3  END;
  4  /
Credit rating over limit (1).  Rating: 3

PL/SQL procedure successfully completed.

SQL>

同じ有効範囲内では、混乱や予期しない結果を回避するためにラベルとサブプログラムに一意の名前を付けます。

例2-27では、ブロックおよびサブプログラムの両方にechoという名前を付けています。 ブロックおよびサブプログラムの両方で、xという変数を宣言しています。 サブプログラム内では、echo.xは、グローバル変数xではなく、ローカル変数xを参照します。

例2-27 同じ有効範囲内で同じ名前を持つラベルとサブプログラム

SQL> <<echo>>
  2  DECLARE
  3    x  NUMBER := 5;
  4
  5    PROCEDURE echo AS
  6      x  NUMBER := 0;
  7    BEGIN
  8      DBMS_OUTPUT.PUT_LINE('x = ' || x);
  9      DBMS_OUTPUT.PUT_LINE('echo.x = ' || echo.x);
 10    END;
 11
 12  BEGIN
 13     echo;
 14  END;
 15  /
x = 0
echo.x = 0

PL/SQL procedure successfully completed.

SQL>

例2-28では、ブロックおよびサブプログラムの両方にechoという名前を付けています。 ブロックおよびサブプログラムの両方で、xという変数を宣言しています。 サブプログラム内では、echo.xは、グローバル変数xではなく、ローカル変数xを参照します。

例2-28では、外側のブロックに対して2つのラベルcompute_ratioanother_labelが存在します。 2番目のラベルは、内側のブロックで再利用されます。 内側のブロック内では、another_label.denominatorはローカル変数denominatorを参照し、グローバル変数denominatorを参照しません。このため、ZERO_DIVIDEエラーが発生します。

例2-28 複数の重複したラベルを使用するブロック

SQL> <<compute_ratio>>
  2  <<another_label>>
  3  DECLARE
  4    numerator   NUMBER := 22;
  5    denominator NUMBER := 7;
  6  BEGIN
  7    <<another_label>>
  8    DECLARE
  9      denominator NUMBER := 0;
 10    BEGIN
 11      DBMS_OUTPUT.PUT_LINE('Ratio with compute_ratio.denominator = ');
 12      DBMS_OUTPUT.PUT_LINE(numerator/compute_ratio.denominator);
 13
 14      DBMS_OUTPUT.PUT_LINE('Ratio with another_label.denominator = ');
 15      DBMS_OUTPUT.PUT_LINE(numerator/another_label.denominator);
 16
 17    EXCEPTION
 18      WHEN ZERO_DIVIDE THEN
 19        DBMS_OUTPUT.PUT_LINE('Divide-by-zero error: can''t divide '
 20          || numerator || ' by ' || denominator);
 21      WHEN OTHERS THEN
 22        DBMS_OUTPUT.PUT_LINE('Unexpected error.');
 23    END inner_label;
 24  END compute_ratio;
 25  /
Ratio with compute_ratio.denominator =
3.14285714285714285714285714285714285714
Ratio with another_label.denominator =
Divide-by-zero error: cannot divide 22 by 0

PL/SQL procedure successfully completed.

SQL>

変数への値の代入

変数の宣言時にデフォルト値を代入する(「変数」を参照)か、または変数の宣言後に代入文を使用して値を代入できます。 たとえば、次の文では変数bonusの古い値を上書きして、新しい値を代入します。

bonus := salary * 0.15;

代入演算子(:=)の後に続く式は、複雑なものでもかまいませんが、そのデータ型は変数のデータ型と同じか、または変数のデータ型に変換できるものである必要があります。

変数は、ブロックまたはサブプログラムに入るたびに初期化されます。 デフォルトでは、変数はNULLに初期化されます。 例2-29に示すように、変数を明示的に初期化しないかぎり、その値はNULLです。

例2-29 デフォルトでNULLに初期化される変数

SQL> DECLARE
  2    counter INTEGER;
  3  BEGIN
  4     counter := counter + 1;
  5
  6     IF counter IS NULL THEN
  7        DBMS_OUTPUT.PUT_LINE('counter is NULL.');
  8     END IF;
  9  END;
 10  /
counter is NULL.

PL/SQL procedure successfully completed.

SQL>

予期しない結果を避けるため、値を代入する前に変数を参照しないでください。

ここでのトピック:

ブール値の代入

ブール変数に代入できるのは、リテラルまたは式の結果としての値TRUEFALSEおよびNULLのみです。

例2-30では、ブール変数doneはデフォルトでNULLに初期化され、その後、リテラル値FALSEが代入され、リテラルのブール値と比較されて、ブール式の値が代入されています。

例2-30 ブール値の代入

SQL> DECLARE
  2    done    BOOLEAN;            -- Initialize to NULL by default
  3    counter NUMBER := 0;
  4  BEGIN
  5    done := FALSE;              -- Assign literal value
  6    WHILE done != TRUE          -- Compare to literal value
  7    LOOP
  8      counter := counter + 1;
  9      done := (counter > 500);  -- Assign value of BOOLEAN expression
 10    END LOOP;
 11  END;
 12  /

PL/SQL procedure successfully completed.

SQL>

PL/SQL変数へのSQL問合せ結果の代入

SELECT INTO文を使用しても変数に値を代入できます。 例2-31に示すように、SELECTリストの項目ごとに、対応する型互換の変数がINTOリストに存在している必要があります。

例2-31 変数への問合せ結果の代入

SQL> DECLARE
  2    emp_id    employees.employee_id%TYPE := 100;
  3    emp_name  employees.last_name%TYPE;
  4    wages     NUMBER(7,2);
  5  BEGIN
  6    SELECT last_name, salary + (salary * nvl(commission_pct,0))
  7      INTO emp_name, wages
  8        FROM employees
  9          WHERE employee_id = emp_id;
 10
 11    DBMS_OUTPUT.PUT_LINE
 12      ('Employee ' || emp_name || ' might make ' || wages);
 13  END;
 14  /
Employee King might make 24000

PL/SQL procedure successfully completed.

SQL>

SQLにはBOOLEAN型がないため、列の値を選択してBOOLEAN変数に代入することはできません。 変数の値が未定義の場合を含め、DML文での変数の代入の詳細は、「データ操作言語(DML)文」を参照してください。

PL/SQLの式および比較

最も単純なPL/SQL式は変数1つで構成され、その変数の値が式の値になります。 任意の複雑なPL/SQL式は、オペランドと演算子を使用して作成できます。 オペランドとは、変数、定数、リテラル、プレースホルダまたはファンクション・コールのことです。 演算子は、単項またはバイナリのいずれかで、それぞれ1つのオペランドまたは2つのオペランドに対して操作を実行します。 単項演算子の例としては、否定(-)があります。 バイナリ演算子の例としては、加算(+)があります。

単純な算術式の例を次に示します。

-X / 2 + 3

PL/SQLは、演算子が指定する方法でオペランドの値を組み合せて、式を評価します。 式は常に1つの値を戻します。 PL/SQLは、式の内容と、式が使用されているコンテキストに基づいてこの値のデータ型を決定します。

ここでのトピック:

連結演算子

連結演算子(||)は、ある文字列オペランドを別の文字列オペランドに追加します。 各文字列には、CHARVARCHAR2CLOBまたはこれらと同等のUnicodeで使用可能な型を使用できます。 一方の文字列がCLOBの場合、結果は一時的なCLOBになります。それ以外の場合は、VARCHAR2値になります。

例2-32およびこのマニュアル内のその他の多くの例で、連結演算子を使用しています。

例2-32 連結演算子

SQL> DECLARE
  2    x VARCHAR2(4) := 'suit';
  3    y VARCHAR2(4) := 'case';
  4  BEGIN
  5    DBMS_OUTPUT.PUT_LINE (x || y);
  6  END;
  7  /
suitcase

PL/SQL procedure successfully completed.

SQL>

演算子の優先順位

式内の演算は、優先順位に応じて評価されます。 表2-2に、優先順位の高い順に演算子を示します。 同じ優先順位の演算子は、特に順序を考慮せずに適用されます。

表2-2 演算子の優先順位

演算子 演算

**


指数

+, -

恒等、否定

*, /

乗算、除算

+, -, ||

加算、減算、連結

=, <, >, <=, >=, <>, !=, ~=^=IS NULLLIKEBETWEENIN

比較

NOT

論理否定

AND

論理積

OR

論理和


カッコを使用すると、評価の順序を制御できます。 カッコがネストされている場合は、最も深くネストされた副式が最初に評価されます。 カッコを使用して評価の順序を制御する必要がない場合でも、カッコを使用してわかりやすくすることができます。 (例2-33のSQLの組込みファンクションTO_CHARは、引数に相当する文字を戻します。 TO_CHARの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。)

例2-33 演算子の優先順位

SQL> DECLARE
  2    salary      NUMBER := 60000;
  3    commission  NUMBER := 0.10;
  4  BEGIN
  5    -- Division has higher precedence than addition:
  6
  7    DBMS_OUTPUT.PUT_LINE('5 + 12 / 4 = ' || TO_CHAR(5 + 12 / 4));
  8    DBMS_OUTPUT.PUT_LINE('12 / 4 + 5 = ' || TO_CHAR(12 / 4 + 5));
  9
 10    -- Parentheses override default operator precedence:
 11
 12    DBMS_OUTPUT.PUT_LINE('8 + 6 / 2 = ' || TO_CHAR(8 + 6 / 2));
 13    DBMS_OUTPUT.PUT_LINE('(8 + 6) / 2 = ' || TO_CHAR((8 + 6) / 2));
 14
 15    -- Most deeply nested subexpression is evaluated first:
 16
 17    DBMS_OUTPUT.PUT_LINE('100 + (20 / 5 + (7 - 3)) = '
 18                         || TO_CHAR(100 + (20 / 5 + (7 - 3))));
 19
 20    -- Parentheses, even when unnecessary, improve readability:
 21
 22    DBMS_OUTPUT.PUT_LINE('(salary * 0.05) + (commission * 0.25) = '
 23                         || TO_CHAR((salary * 0.05) + (commission * 0.25))
 24                        );
 25
 26    DBMS_OUTPUT.PUT_LINE('salary * 0.05 + commission * 0.25 = '
 27                         || TO_CHAR(salary * 0.05 + commission * 0.25)
 28                        );
 29  END;
 30  /
5 + 12 / 4 = 8
12 / 4 + 5 = 8
8 + 6 / 2 = 11
(8 + 6) / 2 = 7
100 + (20 / 5 + (7 - 3)) = 108
(salary * 0.05) + (commission * 0.25) = 3000.025
salary * 0.05 + commission * 0.25 = 3000.025

PL/SQL procedure successfully completed.

SQL>

論理演算子

論理演算子ANDORおよびNOTは、表2-3に示す3値論理に従います。 ANDORはバイナリ演算子、NOTは単項演算子です。

表2-3 論理真理値表

x y x AND y x OR y NOT x

TRUE

TRUE

TRUE

TRUE

FALSE

TRUE

FALSE

FALSE

TRUE

FALSE

TRUE

NULL

NULL

TRUE

FALSE

FALSE

TRUE

FALSE

TRUE

TRUE

FALSE

FALSE

FALSE

FALSE

TRUE

FALSE

NULL

FALSE

NULL

TRUE

NULL

TRUE

NULL

TRUE

NULL

NULL

FALSE

FALSE

NULL

NULL

NULL

NULL

NULL

NULL

NULL


NULLを伴う式で予測不可能な結果が発生しないように注意してください。 詳細は、「比較文と条件文でのNULL値の扱い」を参照してください。

表2-3および例2-34に示されているように、両方のオペランドがTRUEである場合にのみ、ANDTRUEを戻します。 (いくつかの例で、例2-34で作成されるprint_booleanプロシージャを使用しています。)

例2-34 AND演算子

SQL> CREATE OR REPLACE PROCEDURE print_boolean (
  2    name   VARCHAR2,
  3    value  BOOLEAN
  4  ) IS
  5  BEGIN
  6    IF value IS NULL THEN
  7      DBMS_OUTPUT.PUT_LINE (name || ' = NULL');
  8    ELSIF value = TRUE THEN
  9      DBMS_OUTPUT.PUT_LINE (name || ' = TRUE');
 10    ELSE
 11      DBMS_OUTPUT.PUT_LINE (name || ' = FALSE');
 12    END IF;
 13  END;
 14  /

Procedure created.

SQL> DECLARE
  2
  3    PROCEDURE print_x_and_y (
  4      x  BOOLEAN,
  5      y  BOOLEAN
  6    ) IS
  7    BEGIN
  8      print_boolean ('x', x);
  9      print_boolean ('y', y);
 10      print_boolean ('x AND y', x AND y);
 11    END;
 12
 13  BEGIN
 14    print_x_and_y (FALSE, FALSE);
 15    print_x_and_y (TRUE, FALSE);
 16    print_x_and_y (FALSE, TRUE);
 17    print_x_and_y (TRUE, TRUE);
 18
 19    print_x_and_y (TRUE, NULL);
 20    print_x_and_y (FALSE, NULL);
 21    print_x_and_y (NULL, TRUE);
 22    print_x_and_y (NULL, FALSE);
 23  END;
 24  /
x = FALSE
y = FALSE
x AND y = FALSE
x = TRUE
y = FALSE
x AND y = FALSE
x = FALSE
y = TRUE
x AND y = FALSE
x = TRUE
y = TRUE
x AND y = TRUE
x = TRUE
y = NULL
x AND y = NULL
x = FALSE
y = NULL
x AND y = FALSE
x = NULL
y = TRUE
x AND y = NULL
x = NULL
y = FALSE
x AND y = FALSE

PL/SQL procedure successfully completed.

SQL>

表2-3および例2-35に示されているように、一方のオペランドがTRUEである場合、ORTRUEを戻します。 (例2-35では、例2-34で作成されたprint_booleanプロシージャを起動します。)

例2-35 OR演算子

SQL> DECLARE
  2
  3    PROCEDURE print_x_or_y (
  4      x  BOOLEAN,
  5      y  BOOLEAN
  6    ) IS
  7    BEGIN
  8      print_boolean ('x', x);
  9      print_boolean ('y', y);
 10      print_boolean ('x OR y', x OR y);
 11    END;
 12
 13  BEGIN
 14    print_x_or_y (FALSE, FALSE);
 15    print_x_or_y (TRUE, FALSE);
 16    print_x_or_y (FALSE, TRUE);
 17    print_x_or_y (TRUE, TRUE);
 18
 19    print_x_or_y (TRUE, NULL);
 20    print_x_or_y (FALSE, NULL);
 21    print_x_or_y (NULL, TRUE);
 22    print_x_or_y (NULL, FALSE);
 23  END;
 24  /
x = FALSE
y = FALSE
x OR y = FALSE
x = TRUE
y = FALSE
x OR y = TRUE
x = FALSE
y = TRUE
x OR y = TRUE
x = TRUE
y = TRUE
x OR y = TRUE
x = TRUE
y = NULL
x OR y = TRUE
x = FALSE
y = NULL
x OR y = NULL
x = NULL
y = TRUE
x OR y = TRUE
x = NULL
y = FALSE
x OR y = NULL

PL/SQL procedure successfully completed.

SQL>

表2-3および例2-36に示されているように、オペランドがNULLでないかぎり、NOTはオペランドの反対の値を戻します。 NULLは値を持たないため、NOT NULLNULLを戻します。 (例2-36では、例2-34で作成されたprint_booleanプロシージャを起動します。)

例2-36 NOT演算子

SQL> DECLARE
  2
  3    PROCEDURE print_not_x (
  4      x  BOOLEAN
  5    ) IS
  6    BEGIN
  7      print_boolean ('x', x);
  8      print_boolean ('NOT x', NOT x);
  9    END;
 10
 11  BEGIN
 12    print_not_x (TRUE);
 13    print_not_x (FALSE);
 14    print_not_x (NULL);
 15  END;
 16  /
x = TRUE
NOT x = FALSE
x = FALSE
NOT x = TRUE
x = NULL
NOT x = NULL

PL/SQL procedure successfully completed.

SQL>

ここでのトピック:

評価の順序

他のすべての演算子と同様に、論理演算子の評価の順序は、表2-2に示されている演算子の優先順位によって決まり、例2-37に示すように、カッコによって変更できます。 (例2-37では、例2-34で作成されたprint_booleanプロシージャを起動します。)

例2-37 論理演算子の評価の順序の変更

SQL> DECLARE
  2    x  BOOLEAN := FALSE;
  3    y  BOOLEAN := FALSE;
  4
  5  BEGIN
  6    print_boolean ('NOT x AND y', NOT x AND y);
  7    print_boolean ('NOT (x AND y)', NOT (x AND y));
  8    print_boolean ('(NOT x) AND y', (NOT x) AND y);
  9  END;
 10  /
NOT x AND y = FALSE
NOT (x AND y) = TRUE
(NOT x) AND y = FALSE

PL/SQL procedure successfully completed.

SQL>

短絡評価

論理式を評価するときに、PL/SQLでは短絡評価を使用します。 これによって、PL/SQLは結果が判別できた時点でただちに式の評価を停止します。 そのため、評価を続ければエラーになるような式でも書くことができます。

例2-38では、短絡評価によって8行目の式でエラーが発生するのを回避しています。

例2-28 短絡評価

SQL> DECLARE
  2    on_hand  INTEGER := 0;
  3    on_order INTEGER := 100;
  4  BEGIN
  5    -- Does not cause divide-by-zero error;
  6    -- evaluation stops after first expression
  7
  8    IF (on_hand = 0) OR ((on_order / on_hand) < 5) THEN
  9      DBMS_OUTPUT.PUT_LINE('On hand quantity is zero.');
 10    END IF;
 11  END;
 12  /
On hand quantity is zero.

PL/SQL procedure successfully completed.

SQL>

on_handの値が0(ゼロ)の場合、左のオペランドはTRUEになるため、PL/SQLは右のオペランドを評価しません。 OR演算子を適用する前に両方のオペランドを評価した場合には、右のオペランドは0による除算エラーになります。

短絡評価は、PL/SQLのIF文、CASE文およびCASE式に適用されます。

比較演算子

比較演算子は式と式を比較します。 比較の結果は、常にTRUEFALSEまたはNULLのいずれかです。 比較演算子は、一般に、SQL DML文のWHERE句と、条件制御文の中で使用します。

比較演算子は、次のとおりです。


注意:

比較演算子にCLOB値を使用すると、一時的なLOB値が作成される場合があります。 一時表領域がこのような値を処理できる大きさであることを確認してください。

表2-4 関係演算子

演算子 意味

=


等しい

<>, !=, ~=, ^=

等しくない

<


より小さい

>

より大きい

<=


より小さいか、等しい

>=

より大きいか、等しい


例2-39では、例2-34で作成されたprint_booleanプロシージャを起動し、関係演算子を含むいくつかの式の値を出力します。

例2-39 関係演算子

SQL> BEGIN
  2    print_boolean ('(2 + 2 =  4)', 2 + 2 = 4);
  3
  4    print_boolean ('(2 + 2 <> 4)', 2 + 2 <> 4);
  5    print_boolean ('(2 + 2 != 4)', 2 + 2 != 4);
  6    print_boolean ('(2 + 2 ~= 4)', 2 + 2 ~= 4);
  7    print_boolean ('(2 + 2 ^= 4)', 2 + 2 ^= 4);
  8
  9    print_boolean ('(1 < 2)', 1 < 2);
 10
 11    print_boolean ('(1 > 2)', 1 > 2);
 12
 13    print_boolean ('(1 <= 2)', 1 <= 2);
 14
 15    print_boolean ('(1 >= 1)', 1 >= 1);
 16  END;
 17  /
(2 + 2 =  4) = TRUE
(2 + 2 <> 4) = FALSE
(2 + 2 != 4) = FALSE
(2 + 2 ~= 4) = FALSE
(2 + 2 ^= 4) = FALSE
(1 < 2) = TRUE
(1 > 2) = FALSE
(1 <= 2) = TRUE
(1 >= 1) = TRUE

PL/SQL procedure successfully completed.

SQL>
IS NULL演算子

IS NULL演算子は、オペランドがNULLの場合はブールTRUEを、NULLではない場合はFALSEを戻します。 NULL値が関係する比較は、常に結果がNULLになります。

値がNULLかどうかをテストするには、例2-34のプロシージャprint_booleanの6行目のように、IF value IS NULLを使用します。

LIKE演算子

LIKE演算子は、文字、文字列またはCLOB値をパターンと比較し、値がパターンと一致した場合はTRUE、一致しなかった場合はFALSEを戻します。

パターンには、アンダースコア(_)およびパーセント記号(%)の2種類の「ワイルドカード」文字を使用できます。 アンダースコアは1つの文字を表します。 パーセント記号(%)は0(ゼロ)個以上の文字を表します。

大/小文字が区別されます。 例2-40に示すように、文字列'Johnson'はパターン'J%s_n'に一致しますが、'J%S_N'には一致しません。

例2-40 LIKE演算子

SQL> DECLARE
  2
  3    PROCEDURE compare (
  4      value   VARCHAR2,
  5      pattern VARCHAR2
  6    ) IS
  7    BEGIN
  8      IF value LIKE pattern THEN
  9        DBMS_OUTPUT.PUT_LINE ('TRUE');
 10      ELSE
 11        DBMS_OUTPUT.PUT_LINE ('FALSE');
 12      END IF;
 13    END;
 14
 15  BEGIN
 16    compare('Johnson', 'J%s_n');
 17    compare('Johnson', 'J%S_N');
 18  END;
 19  /
TRUE
FALSE

PL/SQL procedure successfully completed.

SQL>

パーセント記号やアンダースコアを検索するには、エスケープ文字を定義して、パーセント記号またはアンダースコアの前にそのエスケープ文字を挿入します。

例2-41では、バックスラッシュをエスケープ文字として使用しているため、文字列内のパーセント記号はワイルドカードとしての役割は果たしません。

例2-41 パターン内のエスケープ文字

SQL> DECLARE
  2
  3    PROCEDURE half_off (sale_sign VARCHAR2) IS
  4    BEGIN
  5      IF sale_sign LIKE '50\% off!' ESCAPE '\' THEN
  6        DBMS_OUTPUT.PUT_LINE ('TRUE');
  7      ELSE
  8        DBMS_OUTPUT.PUT_LINE ('FALSE');
  9      END IF;
 10    END;
 11
 12  BEGIN
 13    half_off('Going out of business!');
 14    half_off('50% off!');
 15  END;
 16  /
FALSE
TRUE

PL/SQL procedure successfully completed.

SQL>
BETWEEN演算子

BETWEEN演算子は、指定された範囲に、ある値が含まれているかどうかをテストします。x BETWEEN a AND bは、x >= aおよびx <= bを意味します。

例2-42では、例2-34で作成されたprint_booleanプロシージャを起動し、BETWEEN演算子を含むいくつかの式の値を出力します。

例2-42 BETWEEN演算子

SQL> BEGIN
  2    print_boolean ('2 BETWEEN 1 AND 3', 2 BETWEEN 1 AND 3);
  3    print_boolean ('2 BETWEEN 2 AND 3', 2 BETWEEN 2 AND 3);
  4    print_boolean ('2 BETWEEN 1 AND 2', 2 BETWEEN 1 AND 2);
  5    print_boolean ('2 BETWEEN 3 AND 4', 2 BETWEEN 3 AND 4);
  6  END;
  7  /
2 BETWEEN 1 AND 3 = TRUE
2 BETWEEN 2 AND 3 = TRUE
2 BETWEEN 1 AND 2 = TRUE
2 BETWEEN 3 AND 4 = FALSE

PL/SQL procedure successfully completed.

SQL>
IN演算子

IN演算子は、セット・メンバーシップをテストします。x IN (set)は、xsetのいずれかのメンバーと等しいことを意味します。

例2-43では、例2-34で作成されたprint_booleanプロシージャを起動し、IN演算子を含むいくつかの式の値を出力します。

例2-43 IN演算子

SQL> DECLARE
  2    letter VARCHAR2(1) := 'm';
  3  BEGIN
  4    print_boolean (
  5      'letter IN (''a'', ''b'', ''c'')',
  6      letter IN ('a', 'b', 'c')
  7    );
  8
  9    print_boolean (
 10      'letter IN (''z'', ''m'', ''y'', ''p'')',
 11      letter IN ('z', 'm', 'y', 'p')
 12    );
 13  END;
 14  /
letter IN ('a', 'b', 'c') = FALSE
letter IN ('z', 'm', 'y', 'p') = TRUE

PL/SQL procedure successfully completed.

SQL>

例2-44は、setNULL値が含まれている場合に発生する状況を示しています。 (例2-44では、例2-34で作成されたprint_booleanプロシージャを起動します。)

例2-44 NULL値を含む集合でのIN演算子の使用

SQL> DECLARE
  2    a INTEGER; -- Initialized to NULL by default
  3    b INTEGER := 10;
  4    c INTEGER := 100;
  5  BEGIN
  6    print_boolean ('100 IN (a, b, c)', 100 IN (a, b, c));
  7    print_boolean ('100 NOT IN (a, b, c)', 100 NOT IN (a, b, c));
  8
  9    print_boolean ('100 IN (a, b)', 100 IN (a, b));
 10    print_boolean ('100 NOT IN (a, b)', 100 NOT IN (a, b));
 11
 12    print_boolean ('a IN (a, b)', a IN (a, b));
 13    print_boolean ('a NOT IN (a, b)', a NOT IN (a, b));
 14  END;
 15  /
100 IN (a, b, c) = TRUE
100 NOT IN (a, b, c) = FALSE
100 IN (a, b) = NULL
100 NOT IN (a, b) = NULL
a IN (a, b) = NULL
a NOT IN (a, b) = NULL

PL/SQL procedure successfully completed.

SQL>

ブール式

PL/SQLでは、SQL文の中でもプロシージャ文の中でも、変数と定数を比較できます。 これらの比較はブール式と呼ばれ、関係演算子で区切られた単純式またはコンポジット式で構成されます。 ブール式は一般に論理演算子ANDORおよびNOTで結合されます。 ブール式の結果は常に、TRUEFALSENULLのいずれかになります。

SQL文の中でブール式を使用して、表の中の文が影響を与える列を指定できます。 プロシージャ文では、条件制御の基盤としてブール式が使用されます。

ここでのトピック:

ブール算術式

関係演算子を使用して数値を比較し、等しいか等しくないかを判定できます。 比較は量によるものです。つまり、片方の数値がより大きな量を表す場合、その数値はより大きいとみなされます。 たとえば、次のような代入文があるとします。

number1 := 75;
number2 := 70;

次の式はTRUEになります。

number1 > number2

一般に、実数を比較して等しいかどうかを判定することはお薦めしません。 実数は近似値として格納されます。 たとえば、次のようなIF条件はTRUEにならない可能性があります。

DECLARE
   fraction BINARY_FLOAT := 1/3;
BEGIN
   IF fraction = 11/33 THEN
      DBMS_OUTPUT.PUT_LINE('Fractions are equal (luckily!)');
   END IF;
END;
/

ブール文字式

文字値を比較して、等しいか等しくないかを判定できます。 デフォルトでは、比較は文字列の各バイトのバイナリ値に基づいて行われます。 たとえば、次のような代入文があるとします。

string1 := 'Kathy';
string2 := 'Kathleen';

次の式はTRUEになります。

string1 > string2

初期化パラメータNLS_COMP=ANSIを設定すると、NLS_SORT初期化パラメータで識別される照合順番を比較に使用できます。 照合順番とは、特定の範囲の数値コードが個々の文字に対応しているキャラクタ・セットの内部的な順序のことです。 内部的な順番を表す数値が他方の文字より大きい場合、その文字値はより大きいとみなされます。 この種の文字が照合順番に使用される場所については、言語ごとに規則が異なる場合があります。 たとえば、アクセント記号が付いた文字のソート順序は、バイナリ値が同じであってもデータベース・キャラクタ・セットに応じて異なることがあります。

NLS_SORTパラメータの値によっては、大/小文字およびアクセント記号の有無を区別しない比較を実行できます。 大/小文字を区別しない比較では、オペランドの文字の大/小文字が異なる場合でもTRUEが戻されます。 アクセント記号の有無を区別しない比較は、大/小文字を区別せず、オペランドのアクセント記号またはデリミタ文字が異なる場合でもTRUEが戻されます。 たとえば、大/小文字を区別しない比較では、'True''TRUE'の文字値は同じであるとみなされ、'Cooperate''Co-Operate'および'coöperate' の文字値もすべて同じであるとみなされます。 大/小文字を区別せずに比較するには、NLS_SORTパラメータの通常の値の末尾に_CIを付けます。 アクセント記号の有無を区別せずに比較するには、NLS_SORTの値の末尾に_AIを付けます。

文字値を比較する場合には、ベース型CHARVARCHAR2の間にある意味上の違いを考慮する必要があります。 詳細は、「CHARとVARCHAR2のデータ型の違い」を参照してください。

多くの型は文字型に変換できます。 たとえば、CLOB変数を使用して比較、代入および他の文字操作を実行できます。 実行可能な変換の詳細は、「PL/SQLのデータ型変換」を参照してください。

ブール日付式

日付も比較できます。 比較は時系列によってなされます。つまり、片方の日付がより新しければ、その日付はより大きいとみなされます。 たとえば、次のような代入文があるとします。

date1 := '01-JAN-91';
date2 := '31-DEC-90';

次の式はTRUEになります。

date1 > date2

ブール式のガイドライン

比較する場合は、カッコを使用することをお薦めします。 たとえば次の式で、100 < taxはブール値になりますが、これは数値500と比較できないため、この式は無効です。

100 < tax < 500  -- not allowed

これをデバッグすれば、次の式になります。

(100 < tax) AND (tax < 500)

ブール変数自体を条件として使用できます。ブール変数をTRUE値またはFALSE値と比較する必要はありません。 例2-24では、ループは等価です。

例2-45 条件テストでのブール変数の使用

SQL> DECLARE
  2    done BOOLEAN;
  3  BEGIN
  4    -- The following WHILE loops are equivalent
  5
  6    done := FALSE;
  7    WHILE done = FALSE
  8    LOOP
  9      done := TRUE;
 10    END LOOP;
 11
 12    done := FALSE;
 13    WHILE NOT (done = TRUE)
 14    LOOP
 15      done := TRUE;
 16    END LOOP;
 17
 18    done := FALSE;
 19    WHILE NOT done
 20    LOOP
 21      done := TRUE;
 22    END LOOP;
 23  END;
 24  /

PL/SQL procedure successfully completed.

SQL>

CASE式

CASE文では、単純な式と検索式の2種類の式が使用されます。 これらの式は、その式が使用されるCASE文の種類に対応しています。 詳細は、「単純なCASE文の使用」を参照してください。

ここでのトピック:

単純なCASE式

単純なCASE式は、1つ以上の選択肢から結果を選択して戻します。 CASE式が複数の行にわたるブロックを含む場合でも、CASE式は代入やサブプログラム・コールなどの大きい文の一部を構成する1つの式です。 CASE式は選択子を使用します。選択子は、その値によって戻す代替アクションが決まる式です。

CASE式の書式は、例2-46に示すとおりです。 選択子(grade)の後に1つ以上のWHEN句があり、各句が順番にチェックされます。 選択子の値によって、どの句が評価されるかが決定されます。 選択子の値と最初に一致したWHEN句によって結果値が決定され、後続のWHEN句は評価されません。 一致する句がない場合は、オプションのELSE句が実行されます。

例2-46 CASE文でのWHEN句の使用

SQL> DECLARE
  2    grade CHAR(1) := 'B';
  3    appraisal VARCHAR2(20);
  4  BEGIN
  5    appraisal :=
  6      CASE grade
  7        WHEN 'A' THEN 'Excellent'
  8        WHEN 'B' THEN 'Very Good'
  9        WHEN 'C' THEN 'Good'
 10        WHEN 'D' THEN 'Fair'
 11        WHEN 'F' THEN 'Poor'
 12        ELSE 'No such grade'
 13      END;
 14    DBMS_OUTPUT.PUT_LINE
 15      ('Grade ' || grade || ' is ' || appraisal);
 16  END;
 17  /
Grade B is Very Good

PL/SQL procedure successfully completed.

SQL>

オプションのELSE句の機能は、IF文のELSE句に似ています。 選択子の値がWHEN句のオプションの1つでなければ、ELSE句が実行されます。 ELSE句が指定されておらず、一致するWHEN句がなければ、式はNULLを戻します。

検索CASE式

検索CASE式を使用すると、1つの式を様々な値と比較するのではなく、異なる条件をテストできます。 この式の書式は、例2-47に示すとおりです。

検索CASE式には選択子はありません。 各WHEN句にはブール値を生成する検索条件が含まれており、単一のWHEN句で異なる変数または複数の条件をテストできます。

例2-47 CASE文での検索条件の使用

SQL> DECLARE
  2    grade      CHAR(1) := 'B';
  3    appraisal  VARCHAR2(120);
  4    id         NUMBER  := 8429862;
  5    attendance NUMBER := 150;
  6    min_days   CONSTANT NUMBER := 200;
  7
  8    FUNCTION attends_this_school (id NUMBER)
  9     RETURN BOOLEAN IS
 10    BEGIN
 11      RETURN TRUE;
 12    END;
 13
 14  BEGIN
 15    appraisal :=
 16      CASE
 17        WHEN attends_this_school(id) = FALSE
 18          THEN 'Student not enrolled'
 19        WHEN grade = 'F' OR attendance < min_days
 20          THEN 'Poor (poor performance or bad attendance)'
 21        WHEN grade = 'A' THEN 'Excellent'
 22        WHEN grade = 'B' THEN 'Very Good'
 23        WHEN grade = 'C' THEN 'Good'
 24        WHEN grade = 'D' THEN 'Fair'
 25        ELSE 'No such grade'
 26      END;
 27    DBMS_OUTPUT.PUT_LINE
 28      ('Result for student ' || id || ' is ' || appraisal);
 29  END;
 30  /
Result for student 8429862 is Poor (poor performance or bad attendance)

PL/SQL procedure successfully completed.

SQL>

検索条件は順番に評価されます。 各検索条件のブール値によって、どのWHEN句が実行されるかが決定されます。 検索条件がTRUEになると、そのWHEN句が実行されます。 WHEN句が1つでも実行された後は、後続の検索条件は評価されません。 TRUEになる検索条件がなければ、オプションのELSE句が実行されます。 WHEN句が実行されず、ELSE句が指定されていなければ、式の値はNULLとなります。

比較文と条件文でのNULL値の扱い

NULL値を使用する場合は、次の規則に注意してください。

  • NULL値が関係する比較は、常に結果がNULLになります。

  • 論理演算子NOTNULL値に適用すると、NULLが戻ります。

  • 条件制御文において条件がNULLになる場合、関連する一連の文は実行されません。

  • 単純なCASE文中の式またはCASE式がNULLになる場合は、WHEN NULLを使用して一致させることができません。 かわりに、検索CASE構文をWHEN expression IS NULLとともに使用します。

例2-48では、xyが等しくないため、一連の文が実行されることが予測されます。 ただし、NULL値は予測不可能です。 そのため、xyが等しいかどうかは不明です。 したがって、IF条件はNULLになり、一連の文は実行されずにバイパスされます。

例2-48 等しくない比較でのNULL値

SQL> DECLARE
  2    x NUMBER := 5;
  3    y NUMBER := NULL;
  4  BEGIN
  5    IF x != y THEN  -- yields NULL, not TRUE
  6      DBMS_OUTPUT.PUT_LINE('x != y');  -- not executed
  7    ELSIF x = y THEN -- also yields NULL
  8      DBMS_OUTPUT.PUT_LINE('x = y');
  9    ELSE
 10      DBMS_OUTPUT.PUT_LINE
 11        ('Can''t tell if x and y are equal or not.');
 12     END IF;
 13  END;
 14  /
Can't tell if x and y are equal or not.

PL/SQL procedure successfully completed.

SQL>

例2-49では、abが等しいため、一連の文が実行されることが予測されます。 ただし、等号条件が成立するかどうかは不明であるため、IF条件はNULLになり、一連の文は実行されずにバイパスされます。

例2-49 等しい比較でのNULL値

SQL> DECLARE
  2    a NUMBER := NULL;
  3    b NUMBER := NULL;
  4  BEGIN
  5    IF a = b THEN  -- yields NULL, not TRUE
  6      DBMS_OUTPUT.PUT_LINE('a = b');  -- not executed
  7    ELSIF a != b THEN  -- yields NULL, not TRUE
  8      DBMS_OUTPUT.PUT_LINE('a != b');  -- not executed
  9    ELSE
 10      DBMS_OUTPUT.PUT_LINE('Can''t tell if two NULLs are equal');
 11    END IF;
 12  END;
 13  /
Can't tell if two NULLs are equal

PL/SQL procedure successfully completed.

SQL>

ここでのトピック:

NULL値とNOT演算子

論理演算子NOTNULL値に適用すると、NULLが戻されます。 このため、次の2つのIF文は必ずしも等価ではありません。

SQL> DECLARE
  2    x    INTEGER := 2;
  3    Y    INTEGER := 5;
  4    high INTEGER;
  5  BEGIN
  6    IF x > y THEN high := x;
  7    ELSE high := y;
  8    END IF;
  9
 10    IF NOT x > y THEN high := y;
 11    ELSE high := x;
 12    END IF;
 13  END;
 14  /

PL/SQL procedure successfully completed.

SQL>

IF条件がFALSEまたはNULLになると、ELSE句内の一連の文が実行されます。 xyのどちらもNULLではない場合、両方のIF文で同じ値がhighに代入されます。 ただし、xyのどちらかがNULLの場合、1番目のIF文はyの値をhighに代入しますが、2番目のIF文はxの値をhighに代入します。

NULL値と長さ0(ゼロ)の文字列

PL/SQLは長さが0(ゼロ)の文字値をすべてNULL値とみなします。 これには文字関数やブール式によって戻された値が含まれます。 たとえば、次の文ではターゲットの変数にNULLを代入します。

SQL> DECLARE
  2     null_string  VARCHAR2(80) := TO_CHAR('');
  3     address      VARCHAR2(80);
  4     zip_code     VARCHAR2(80) := SUBSTR(address, 25, 0);
  5     name         VARCHAR2(80);
  6     valid        BOOLEAN      := (name != '');
  7  BEGIN
  8    NULL;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL>

NULL文字列かどうかをテストする場合は、次のようにIS NULL演算子を使用してください。

IF v_string IS NULL THEN ...

NULL値と連結演算子

連結演算子はNULLオペランドを無視します。 次に例を示します。

SQL> BEGIN
  2    DBMS_OUTPUT.PUT_LINE ('apple' || NULL || NULL || 'sauce');
  3  END;
  4  /
applesauce

PL/SQL procedure successfully completed.

SQL>

組込みファンクションの引数としてのNULL値

組込みファンクションに引数NULLが渡されると、次に示す場合を除いてNULL値が戻されます。

ファンクションDECODEは、先頭の引数を1つまたは複数の検索式と比較します。検索式は結果式と対になっています。 検索式や結果式はNULLの場合があります。 検索に成功すると、対応する結果が戻されます。 例2-50では、列manager_idNULLの場合、DECODEは値'nobody'を戻します。

例2-50 DECODEファンクションに対する引数としてのNULL値

SQL> DECLARE
  2    manager  VARCHAR2(40);
  3    name     employees.last_name%TYPE;
  4  BEGIN
  5    -- NULL is a valid argument to DECODE.
  6    -- In this case, manager_id is NULL
  7    -- and the DECODE function returns 'nobody'.
  8
  9    SELECT DECODE(manager_id, NULL, 'nobody', 'somebody'), last_name
 10      INTO manager, name
 11        FROM employees
 12          WHERE employee_id = 100;
 13
 14    DBMS_OUTPUT.PUT_LINE
 15      (name || ' is managed by ' || manager);
 16  END;
 17  /
King is managed by nobody

PL/SQL procedure successfully completed.

SQL>

先頭の引数がNULLの場合、ファンクションNVLは2番目の引数の値を戻します。 例2-51では、問合せで指定された列がNULLの場合、ファンクションは値-1を戻し、従業員が存在しないことを出力に示します。

例2-51 NVLファンクションに対する引数としてのNULL値

SQL> DECLARE
  2    manager employees.manager_id%TYPE;
  3    name    employees.last_name%TYPE;
  4  BEGIN
  5    -- NULL is a valid argument to NVL.
  6    -- In this case, manager_id is null
  7    -- and the NVL function returns -1.
  8
  9    SELECT NVL(manager_id, -1), last_name
 10      INTO manager, name
 11        FROM employees
 12          WHERE employee_id = 100;
 13
 14     DBMS_OUTPUT.PUT_LINE
 15       (name || ' is managed by employee Id: ' || manager);
 16  END;
 17  /
King is managed by employee Id: -1

PL/SQL procedure successfully completed.

SQL>

2番目の引数がNULLの場合、ファンクションREPLACEはオプションの3番目の引数が存在するかどうかにかかわらず、1番目の引数の値を戻します。 たとえば、例2-52REPLACEのコールは、old_stringの値を変更しません。

例2-52 REPLACEファンクションに対する2番目の引数としてのNULL値

SQL> DECLARE
  2    string_type  VARCHAR2(60);
  3    old_string   string_type%TYPE := 'Apples and oranges';
  4    v_string     string_type%TYPE := 'more apples';
  5
  6    -- NULL is a valid argument to REPLACE,
  7    -- but does not match anything,
  8    -- so no replacement is done.
  9
 10    new_string string_type%TYPE := REPLACE(old_string, NULL, v_string);
 11  BEGIN
 12    DBMS_OUTPUT.PUT_LINE('Old string = ' || old_string);
 13    DBMS_OUTPUT.PUT_LINE('New string = ' || new_string);
 14  END;
 15  /
Old string = Apples and oranges
New string = Apples and oranges

PL/SQL procedure successfully completed.

SQL>

3番目の引数がNULLの場合、REPLACEは、1番目の引数から2番目の引数をすべて削除したものを戻します。 たとえば、例2-53REPLACEのコールは、dashed_stringのダッシュを別の文字で置き換えるのではなく、削除します。

例2-53 REPLACEファンクションに対する3番目の引数としてのNULL値

SQL> DECLARE
  2    string_type  VARCHAR2(60);
  3    dashed       string_type%TYPE := 'Gold-i-locks';
  4
  5    -- When the substitution text for REPLACE is NULL,
  6    -- the text being replaced is deleted.
  7
  8    name         string_type%TYPE := REPLACE(dashed, '-', NULL);
  9  BEGIN
 10     DBMS_OUTPUT.PUT_LINE('Dashed name    = ' || dashed);
 11     DBMS_OUTPUT.PUT_LINE('Dashes removed = ' || name);
 12  END;
 13  /
Dashed name    = Gold-i-locks
Dashes removed = Goldilocks

PL/SQL procedure successfully completed.

SQL>

2番目の引数と3番目の引数がNULLの場合、REPLACEは単に1番目の引数を戻します。

PL/SQLエラー・レポート・ファンクション

PL/SQLには、PL/SQL例外処理コードで使用するためのSQLCODESQLERRMの2つの組込みエラー・レポート・ファンクションがあります。 詳細は、「SQLCODEファンクション」および「SQLERRMファンクション」を参照してください。

SQLCODEまたはSQLERRMファンクションは、SQL文では使用できません。

PL/SQLでのSQLファンクションの使用

PL/SQL式では、次のファンクションを除くすべてのSQLファンクションを使用できます。

PL/SQLでは、引数および結果がBINARY_INTEGERであるBITANDのオーバーロードがサポートされています。

PL/SQL式でRAWTOHEXファンクションを使用すると、データ型RAWの引数が受け入れられ、その引数の値を構成するバイトの16進表現でVARCHAR2値が戻されます。 RAW以外の型の引数は、RAWに暗黙的に変換できる場合にのみ指定できます。 この変換は、HEXTORAWファンクションの有効な引数であるCHARVARCHAR2およびLONGの値と、最大16380バイトのLONG RAWおよびBLOBの値に対して実行可能です。


参照:

SQLファンクションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

条件付きコンパイル

条件付きコンパイルを使用すると、ソース・コードを削除することなく、PL/SQLアプリケーションの機能をカスタマイズできます。 たとえば、条件付きコンパイルを使用して、PL/SQLアプリケーションを次のようにカスタマイズできます。

ここでのトピック:

条件付きコンパイルの動作方法

条件付きコンパイルでは、選択ディレクティブ、問合せディレクティブおよびエラー・ディレクティブを使用してコンパイルのソース・テキストを指定します。 問合せディレクティブでは、PLSQL_CCFLAGSコンパイル・パラメータ(「PL/SQLユニットおよびコンパイル・パラメータ」を参照)の名前/値ペアによって設定された値にアクセスします。 選択ディレクティブでは、問合せディレクティブまたは静的パッケージ定数をテストできます。

DBMS_DB_VERSIONパッケージでは、条件付きコンパイルに使用できるデータベースのバージョンおよびリリース定数が提供されます。 DBMS_PREPROCESSORパッケージでは、PL/SQLユニットの条件付きコンパイル・ディレクティブによって選択される処理後のソース・テキストにアクセスするためのサブプログラムが提供されます。


注意:

条件付きコンパイル機能および関連するPL/SQLパッケージは、リリース10.1.0.4以上のOracle Databaseで使用可能です。

ここでのトピック:

条件付きコンパイルの制御トークン

条件付きコンパイルのトリガー文字$で、これによってアプリケーションがコンパイルされる前に処理されるコードが識別されます。 条件付きコンパイル制御トークンの形式は次のとおりです。

preprocessor_control_token ::= $plsql_identifier

$は識別子名の先頭に置く必要があり、$と名前の間に空白を入れることはできません。 $は識別子名に埋め込むこともできますが、特別な意味は持ちません。 予約済のプリプロセッサ制御トークンは、$IF$THEN$ELSE$ELSIF$ENDおよび$ERRORです。 条件付きコンパイル制御トークンの使用例は、例2-56を参照してください。

条件付きコンパイルの選択ディレクティブの使用

条件付きコンパイルの選択ディレクティブでは、静的な式を評価して、コンパイルに含めるテキストを判定します。 選択ディレクティブの形式は次のとおりです。

$IF boolean_static_expression $THEN text
  [$ELSIF boolean_static_expression $THEN text]
  [$ELSE text]
$END

boolean_static_expressionは、静的なBOOLEAN式である必要があります。 静的なBOOLEAN式の説明は、「条件付きコンパイルでの静的な式の使用」を参照してください。 PL/SQLのIF-THEN制御構造の詳細は、「条件テスト(IF文およびCASE文)」を参照してください。

条件付きコンパイルのエラー・ディレクティブの使用

エラー・ディレクティブ$ERRORでは、ユーザー定義の例外を呼び出します。形式は次のとおりです。

$ERROR varchar2_static_expression $END

varchar2_static_expressionは、静的なVARCHAR2式である必要があります。 静的なVARCHAR2式の説明は、「条件付きコンパイルでの静的な式の使用」を参照してください。 また、例2-55を参照してください。

条件付きコンパイルの問合せディレクティブの使用

問合せディレクティブは、コンパイル環境のチェックに使用します。 問合せディレクティブの形式は次のとおりです。

inquiry_directive ::= $$id

問合せディレクティブは、「条件付きコンパイルでの事前定義問合せディレクティブの使用」に示すとおり、事前定義またはユーザー定義にできます。 次に、条件付きコンパイルが問合せディレクティブを解決しようとする場合の処理フローの順序を示します。

  1. idは、$$idの形式で、問合せディレクティブとして検索キーに使用します。

  2. 2パス・アルゴリズムは、次のように進行します。

    PLSQL_CCFLAGSコンパイル・パラメータの文字列が右から左へスキャンされ、idで一致名(大/小文字を区別しない)が検索されて、検出されると完了します。

    事前定義された問合せディレクティブが検索され、検出されると完了します。

  3. $$idを値に解決できない場合は、ソース・テキストがラップされていなくてもPLW-6003警告メッセージがレポートされます。 リテラルNULLは、未定義の問合せディレクティブの値として代入されます。 PL/SQLコードがラップされている場合は、未定義の問合せディレクティブが示されないように、警告メッセージが無効になります。

たとえば、次のようなセッション設定があるとします。

ALTER SESSION SET
  PLSQL_CCFLAGS = 'plsql_ccflags:true, debug:true, debug:0';

$$debugの値は0で、$$plsql_ccflagsの値はTRUEです。 $$plsql_ccflagsの値は、PLSQL_CCFLAGSコンパイラ・パラメータの値内のユーザー定義のPLSQL_CCFLAGSを解決します。 これは、ユーザー定義のディレクティブは事前定義のディレクティブをオーバーライドするためです。

次のセッション設定について考えてみます。

ALTER SESSION SET PLSQL_CCFLAGS = 'debug:true'

$$debugの値はTRUE$$plsql_ccflagsの値は'debug:true'$$my_idの値はリテラルNULLです。$$my_idを使用すると、ソース・テキストがラップされていなくても、PLW-6003が呼び出されます。

問合せディレクティブの使用例は、例2-56を参照してください。

条件付きコンパイルでの事前定義問合せディレクティブの使用

条件式で使用できる事前定義問合せディレクティブ名は、次のとおりです。

  • 行番号を示すPLS_INTEGERリテラル値であるPLSQL_LINEは、現行のPL/SQLユニットの$$PLSQL_LINEを参照します。

    条件式の$$PLSQL_LINEの例を次に示します。

    $IF $$PLSQL_LINE = 32 $THEN ...
    
  • VARCHAR2リテラル値であるPLSQL_UNITは、現行のPL/SQLユニットを示しています。

    名前付きPL/SQLユニットの場合は、$$PLSQL_UNITにユニット名が含まれますが、ユニット名に限定されない場合があります。 無名ブロックの場合は、$$PLSQL_UNITに空の文字列が含まれます。

    条件式の$$PLSQL_UNITの例を次に示します。

    IF $$PLSQL_UNIT = 'AWARD_BONUS' THEN ...
    

    前述の例は、通常のPL/SQLでのPLSQL_UNITの使用を示しています。 $$PLSQL_UNIT = 'AWARD_BONUS'は静的な式ではなくVARCHAR2の比較であるため、$IFではサポートされません。 PLSQL_UNITでの有効な$IFの使用方法の1つに、次のように無名ブロックを決定することがあります。

    $IF $$PLSQL_UNIT IS NULL $THEN ...
    
  • PL/SQLコンパイル・パラメータ

リテラルPLSQL_LINEおよびPLSQL_UNITの値は、コンパイル・パラメータPLSQL_CCFLAGSで明示的に定義できます。 コンパイル・パラメータの詳細は、「PL/SQLユニットおよびコンパイル・パラメータ」を参照してください。

条件付きコンパイルでの静的な式の使用

条件付きコンパイルの処理では、コンパイラで完全に評価できる静的な式のみが使用できます。 変数への参照を含むすべての式またはPL/SQLの実行が必要なファンクションは、コンパイル中には使用できず、評価されません。 PL/SQLのデータ型の詳細は、「事前定義のPL/SQLのスカラー・データ型およびサブタイプ」を参照してください。

静的な式とは、静的なBOOLEANPLS_INTEGERまたはVARCHAR2式のいずれかです。 パッケージで宣言される静的定数も静的な式です。

ここでのトピック:

静的なブール式

静的なBOOLEAN式には次のものが含まれます。

  • TRUEFALSEおよびリテラルNULL

  • xおよびyは、静的なPLS_INTEGER式です。

    • x > y

    • x < y

    • x >= y

    • x <= y

    • x = y

    • x <> y

  • xおよびyは、PLS_INTEGERブール式です。

    • NOT x

    • x AND y

    • x OR y

    • x > y

    • x >= y

    • x = y

    • x <= y

    • x <> y

  • xは静的な式です。

    • x IS NULL

    • x IS NOT NULL

静的なPLS_INTEGER式

静的なPLS_INTEGER式には次のものが含まれます。

  • -2147483648から2147483647およびリテラルNULL

静的なVARCHAR2式

静的なVARCHAR2式には次のものが含まれます。

  • 'abcdef'

  • 'abc' || 'def'

  • リテラルNULL

  • TO_CHAR(x)xは静的なPLS_INTEGER式)

  • TO_CHAR(x f, n)xは静的なPLS_INTEGER式で、fnは静的なVARCHAR2式)

  • x || yxおよびyは、静的なVARCHAR2式またはPLS_INTEGER式)

静的定数

静的定数は次のパッケージ仕様部で宣言されます。

static_constant CONSTANT data_type := static_expression;

有効な静的定数の宣言は、次のとおりです。

  • 宣言されたdata_typestatic_expressionの型が同じ場合

  • static_expressionが静的な式である場合

  • data_typeBOOLEANまたはPLS_INTEGERのいずれかである場合

静的定数はパッケージ仕様部で宣言する必要があり、package_nameパッケージ本体内にある場合でも、package_name.constant_nameとして参照する必要があります。

静的パッケージ定数が、PL/SQLユニットで有効な選択ディレクティブのBOOLEAN式として使用されると、条件付きコンパイルのメカニズムによって、参照されるパッケージへの依存性が自動的に生成されます。 パッケージが変更されると依存ユニットは無効になり、再コンパイルして変更を取得する必要があります。 依存性を生成できるのは、有効な静的な式のみです。

複数のPL/SQLユニットの条件付きコンパイルを制御する静的定数を持つパッケージを使用する場合は、パッケージ仕様部のみを作成し、複数の依存性のために、そのパッケージ仕様部を条件付きコンパイルの制御専用にします。 個々のユニットの条件付きコンパイルを制御するには、PL/SQLコンパイル・パラメータPLSQL_CCFLAGSに特定のフラグを設定できます。 PL/SQLコンパイル・パラメータの詳細は、「PL/SQLユニットおよびコンパイル・パラメータ」を参照してください。

例2-54では、my_debugパッケージは、デバッグを制御し、複数のPL/SQLユニットをトレースするための定数を定義します。 この例では、定数debugおよびtraceはプロシージャmy_proc1およびmy_proc2の静的な式で使用され、プロシージャからの依存性をmy_debugに生成します。

例2-54 静的定数の使用

SQL> CREATE PACKAGE my_debug IS
  2    debug CONSTANT BOOLEAN := TRUE;
  3    trace CONSTANT BOOLEAN := TRUE;
  4  END my_debug;
  5  /

Package created.

SQL> CREATE PROCEDURE my_proc1 IS
  2  BEGIN
  3    $IF my_debug.debug $THEN
  4      DBMS_OUTPUT.put_line('Debugging ON');
  5    $ELSE
  6      DBMS_OUTPUT.put_line('Debugging OFF');
  7    $END
  8  END my_proc1;
  9  /

Procedure created.

SQL> CREATE PROCEDURE my_proc2 IS
  2  BEGIN
  3    $IF my_debug.trace $THEN
  4      DBMS_OUTPUT.put_line('Tracing ON');
  5    $ELSE DBMS_OUTPUT.put_line('Tracing OFF');
  6    $END
  7  END my_proc2;
  8  /

Procedure created.

SQL>

定数の値の1つを変更すると、パッケージのすべての依存ユニットが新しい値で再コンパイルされます。 たとえば、debugの値をFALSEに変更すると、my_proc1がデバッグ・コードなしで再コンパイルされます。my_proc2も再コンパイルされますが、traceの値が変更されていないため、my_proc2は変更されません。

DBMS_DB_VERSIONパッケージ定数の使用

DBMS_DB_VERSIONパッケージは、条件付きコンパイルの単純な選択を行う場合に役立つ定数を提供します。 PLS_INTEGER定数VERSIONおよびRELEASEは、現行のOracle Databaseバージョンとリリース番号を識別します。 ブール定数VER_LE_9VER_LE_9_1VER_LE_9_2VER_LE_10VER_LE_10_1およびVER_LE_10_2は、次のように、TRUEまたはFALSEと評価されます。

  • VER_LE_vは、データベース・バージョンがv以下の場合にTRUEと評価され、そうでない場合はFALSEと評価されます。

  • VER_LE_v_rは、データベース・バージョンがv以下で、リリースがr以下の場合にTRUEと評価され、そうでない場合はFALSEと評価されます。

  • Oracle Database 10gリリース1(10.1)以下を表す定数はすべてFALSEになります。

例2-55に、条件付きコンパイルでのDBMS_DB_VERSION定数の使用例を示します。 Oracle Databaseのバージョンとリリースの両方がチェックされます。 ここでは、$ERRORの使用例も示します。

例2-55 DBMS_DB_VERSION定数の使用

SQL> BEGIN
  2    $IF DBMS_DB_VERSION.VER_LE_10_1 $THEN
  3      $ERROR 'unsupported database release'
  4    $END
  5    $ELSE
  6      DBMS_OUTPUT.PUT_LINE
  7        ('Release ' || DBMS_DB_VERSION.VERSION || '.' ||
  8         DBMS_DB_VERSION.RELEASE || ' is supported.');
  9
 10    -- This COMMIT syntax is newly supported in 10.2:
 11    COMMIT WRITE IMMEDIATE NOWAIT;
 12  $END
 13  END;
 14  /
Release 11.1 is supported.

PL/SQL procedure successfully completed.

SQL>

DBMS_DB_VERSIONパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

条件付きコンパイルの例

この項では、条件付きコンパイルの使用例を示します。

ここでのトピック:

条件付きコンパイルを使用してデータベースのバージョンのコードを指定する方法

例2-56では、BINARY_DOUBLEデータ型をデータベースのPL/SQLユニットの計算で使用できるかどうかを、条件付きコンパイルを使用して判断します。 BINARY_DOUBLEデータ型は、10g以上のデータベースのバージョンでのみ使用できます。

例2-56 データベースのバージョンでの条件付きコンパイルの使用

SQL> -- Set flags for displaying debugging code and tracing info:
SQL>
SQL> ALTER SESSION SET PLSQL_CCFLAGS =
  2    'my_debug:FALSE, my_tracing:FALSE';

Session altered.

SQL>
SQL> CREATE OR REPLACE PACKAGE my_pkg AS
  2    SUBTYPE my_real IS
  3      $IF DBMS_DB_VERSION.VERSION < 10 $THEN
  4        NUMBER;
  5        -- Check database version
  6      $ELSE
  7        BINARY_DOUBLE;
  8      $END
  9
 10      my_pi my_real;
 11      my_e my_real;
 12  END my_pkg;
 13  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY my_pkg AS
  2  BEGIN
  3    -- Set values for future calculations based on DB version
  4
  5    $IF DBMS_DB_VERSION.VERSION < 10 $THEN
  6      my_pi := 3.14159265358979323846264338327950288420;
  7      my_e  := 2.71828182845904523536028747135266249775;
  8    $ELSE
  9      my_pi := 3.14159265358979323846264338327950288420d;
 10      my_e  := 2.71828182845904523536028747135266249775d;
 11    $END
 12  END my_pkg;
 13  /

Package body created.

SQL> CREATE OR REPLACE PROCEDURE circle_area(radius my_pkg.my_real) IS
  2    my_area      my_pkg.my_real;
  3    my_data_type  VARCHAR2(30);
  4  BEGIN
  5    my_area := my_pkg.my_pi * radius;
  6
  7    DBMS_OUTPUT.PUT_LINE
  8      ('Radius: ' || TO_CHAR(radius) || ' Area: ' || TO_CHAR(my_area));
  9
 10    $IF $$my_debug $THEN
 11      -- If my_debug is TRUE, run debugging code
 12      SELECT DATA_TYPE INTO my_data_type
 13        FROM USER_ARGUMENTS
 14          WHERE OBJECT_NAME = 'CIRCLE_AREA'
 15            AND ARGUMENT_NAME = 'RADIUS';
 16
 17       DBMS_OUTPUT.PUT_LINE
 18         ('Data type of the RADIUS argument is: ' || my_data_type);
 19    $END
 20  END;
 21  /

Procedure created.

SQL>

DBMS_PREPROCESSORプロシージャを使用してソース・テキストの印刷または取出しを行う方法

DBMS_PREPROCESSORサブプログラムは、条件付きコンパイル・ディレクティブの処理後に、PL/SQLユニットの処理後のソース・テキストを印刷または取り出します。 この処理後のテキストは、有効なPL/SQLユニットのコンパイルに使用する実際のソースです。 例2-57に、PRINT_POST_PROCESSED_SOURCEプロシージャで例2-56my_pkgの処理後の形式を印刷する方法を示します。

例2-57 PRINT_POST_PROCESSED_SOURCEを使用したソース・コードの表示

SQL> CALL DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE
  2    ('PACKAGE', 'HR', 'MY_PKG');
PACKAGE my_pkg AS
SUBTYPE my_real IS
BINARY_DOUBLE;
my_pi my_real;
my_e my_real;
END my_pkg;

Call completed.

SQL>

PRINT_POST_PROCESSED_SOURCEは、非選択テキストを空白に置き換えます。 処理後のテキストに含まれない例2-56のコードの行は、空白行として表されます。 DBMS_PREPROCESSORパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

条件付きコンパイルの制限

条件付きコンパイル・ディレクティブは、オブジェクト型の仕様部やスキーマ・レベルのネストした表またはVARRAYの仕様部では使用できません。 依存する型の属性構造および依存する表の列構造は、オブジェクト型の仕様部で指定された属性構造によって決定されます。 オブジェクト型の属性構造に対するすべての変更は、それらの変更が依存オブジェクトに適用されるように、決められた方法で実行される必要があります。 変更を適用するには、SQLのALTER TYPE ATTRIBUTE文を使用します。 プリプロセッサ・ディレクティブを使用すると、ALTER TYPE ATTRIBUTE文を使用しなくても、オブジェクト型の属性構造を変更できます。 その結果、依存オブジェクトが非同期になったり、依存表がアクセス不可になる場合があります。

SQLパーサーでは、CREATE OR REPLACE文や無名ブロックの実行などのSQL操作の実行時に、ディレクティブの配置についての制限があります。 これらのSQL操作の実行時、最初の条件付きコンパイル・ディレクティブの位置について、SQLパーサーでは次の制限があります。

  • 条件付きコンパイル・ディレクティブは、オブジェクト型の仕様部やスキーマ・レベルのネストした表またはVARRAYの仕様部では使用できません。

  • パッケージ仕様部、パッケージ本体、型本体および仮パラメータがないスキーマ・レベルのサブプログラムでは、最初の条件付きコンパイル・ディレクティブが、キーワードISまたはASの直後に配置される場合があります。

  • 1つ以上の仮パラメータを持つスキーマ・レベルのサブプログラムでは、最初の条件付きコンパイル・ディレクティブは、ユニット名の後の開きカッコの直後に配置されることがあります。 次に例を示します。

    CREATE OR REPLACE PROCEDURE my_proc (
      $IF $$xxx $THEN i IN PLS_INTEGER $ELSE i IN INTEGER $END
    ) IS BEGIN NULL; END my_proc;
    /
    
  • トリガーまたは無名ブロックでは、トリガー・ブロックにDECLAREセクションがある場合、最初の条件付きコンパイル・ディレクティブは、キーワードBEGINの直後またはキーワードDECLAREの直後に配置される場合があります。

  • 無名ブロックでプレースホルダが使用される場合、条件付きコンパイル内ではこの配置は行われません。 次に例を示します。

    BEGIN
      :n := 1; -- valid use of placeholder
      $IF ... $THEN
        :n := 1; -- invalid use of placeholder
    $END
    

PL/SQLを使用してWebアプリケーションを作成する方法

PL/SQLを使用するとデータベースから直接Webページを生成するアプリケーションを作成できるため、データベースをWeb上で使用可能にし、事務管理部門のデータベースをイントラネット上でアクセス可能にすることができます。

PL/SQL Webアプリケーションのプログラム・フローは、CGI PERLスクリプトのプログラム・フローに似ています。 通常、開発者はCGIスクリプトを使用してWebページを動的に作成しますが、多くの場合それらのスクリプトはデータベースへのアクセスに適していません。 PL/SQLストアド・サブプログラムでWebコンテンツを配信することによって、強力で柔軟なデータベース処理が実現されます。 たとえば、DML、動的SQLおよびカーソルを使用できます。 各HTTPリクエストを処理する新しいCGIプロセスをforkするためのプロセス・オーバーヘッドを解消することもできます。

PL/SQL GatewayとPL/SQL Web Toolkitを使用して、完全にWebブラウザ・ベースのアプリケーションをPL/SQLに実装できます。

PL/SQL Gatewayを使用すると、HTTPリスナーを介してWebブラウザでPL/SQLストアド・サブプログラムを起動できます。PL/SQL Gatewayの1つの実装であるmod_plsqlはOracle HTTP Serverのプラグインであり、WebブラウザでPL/SQLストアド・サブプログラムを起動できるようにします。

PL/SQL Web Toolkitは、実行時にmod_plsqlによって起動されるストアド・サブプログラムを使用するための一般的なインタフェースを提供する一連のPL/SQLパッケージです。


参照:

Webアプリケーションの作成の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

PL/SQLを使用してServer Pagesを作成する方法

PL/SQL Server Pages(PSP)を使用すると、Webページを動的コンテンツで開発できます。 これは、Webページ用にHTMLコードを一度に1行ずつ書き出すストアド・サブプログラムをコーディングする方法の代替手段です。

特殊なタグを使用すると、PL/SQLスクリプトをHTMLソース・コードに埋め込むことができます。 スクリプトは、ページがブラウザなどのWebクライアントによって要求されたときに実行されます。 スクリプトは、パラメータ、データベースへの問合せまたは更新を受け入れることが可能で、結果を示すカスタマイズ済のページを表示できます。

開発中、PSPはページ・レイアウト用の静的部分およびコンテンツ用の動的部分を持つテンプレートのように動作できます。 任意のHTMLオーサリング・ツールを使用してレイアウトを設計できます。プレースホルダは動的コンテンツ用に残します。 次に、コンテンツを生成するPL/SQLスクリプトを作成できます。 終了した後、作成したPSPファイルをストアド・サブプログラムとして単にデータベースにロードします。


参照:

Web Server Pagesの作成の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。