ヘッダーをスキップ

Oracle Database PL/SQLユーザーズ・ガイドおよびリファレンス
10g リリース2(10.2)

B19257-01
目次
目次
索引
索引

戻る 次へ

2 PL/SQL言語の基礎

前の章では、PL/SQLの概要を示しました。この章では、PL/SQLを詳細に説明します。他のプログラミング言語と同様に、PL/SQLにはキャラクタ・セット、予約語、デリミタ、データ型および一定の構文規則があります。

この章の項目は、次のとおりです。

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

PL/SQLプログラムは、特定のキャラクタ・セットを使用したテキストとして作成されます。

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

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

わかりやすくするために、字句単位は空白で区切ることができます。実際には、隣接する識別子は、空白またはデリミタで区切る必要があります。次の行は予約語のENDIFが結合されているため、不正です。

IF x > y THEN high := x; ENDIF; -- 不正です。END IFとする必要があります。

文字列リテラルとコメントの場合を除き、字句単位の中に空白を埋め込むことはできません。たとえば、次の行は代入を表すコンパウンド記号(:=)が分かれているため、不正です。

count : = count + 1; -- 不正です。 :=とする必要があります。

構造を示すために、改行で行を分けたり、空白またはタブで行にインデントを付けることができます。次に示す最初のIF文は、このような方法で形式を整えることによってより見やすくできます。

IF x>y THEN max:=x;ELSE max:=y;END IF;

次の文のほうがより見やすくなります。

IF x > y THEN
  max := x;
ELSE
  max := y;
END IF;

デリミタ

デリミタは、PL/SQLにとって特別な意味を持つ単純記号またはコンパウンド記号です。たとえば、デリミタを使用して加算や減算などの算術演算を表現できます。表2-1に、PL/SQLのデリミタのリストを示します。

表2-1    PL/SQLのデリミタ 
記号  意味 

+ 

加算演算子 

% 

属性のインジケータ 

' 

文字列のデリミタ 

. 

構成要素の選択子 

/ 

除算演算子 

( 

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

) 

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

: 

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

, 

項目のセパレータ 

* 

乗算演算子 

" 

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

= 

関係演算子 

< 

関係演算子 

> 

関係演算子 

@ 

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

; 

文の終了記号 

- 

減算/否定演算子 

:= 

代入演算子 

=> 

結合演算子 

|| 

連結演算子 

** 

指数演算子 

<< 

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

>> 

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

/* 

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

*/ 

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

.. 

範囲演算子 

<> 

関係演算子 

!= 

関係演算子 

~= 

関係演算子 

^= 

関係演算子 

<= 

関係演算子 

>= 

関係演算子 

-- 

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

識別子

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

X
t2
phone#
credit_limit
LastName
oracle$number

識別子は英字1文字でもかまいませんが、後に英字、数字、ドル記号、アンダースコアおよびシャープ記号を続けることもできます。次の例のように、ハイフン、スラッシュ、空白などの文字は使用できません。

mine&yours: アンパサンドがあるため使用不可
debit-amount: ハイフンがあるため使用不可
on/off: スラッシュがあるため使用不可
user id: スペースがあるため使用不可

ドル記号、アンダースコアおよびシャープ記号を隣接して使用したり、先頭以外の位置で使用することができます。

money$$$tree
SN##
try_again_

識別子では大文字と小文字が使用でき、両者の混用もできます。PL/SQLでは、文字列リテラルと文字リテラルの中を除いて、大/小文字は区別されません。したがって、2つの識別子の違いが英字の大/小文字の違いのみであれば、PL/SQLは同じ識別子とみなします。

lastname
LastName -- lastnameと同じ
LASTNAME -- lastnameおよびLastNameと同じ

識別子のサイズは30文字以内にする必要があります。ドル記号、アンダースコアおよびシャープ記号を含むすべての文字が意味を持ちます。たとえば、PL/SQLは、次の2つの識別子を別のものとして扱います。

lastname
last_name

識別子は、内容がわかりやすいものにしてください。cpmのようなあいまいな名前は避けます。かわりに、cost_per_thousandのように意味のわかりやすい名前を使用してください。

予約語

識別子には、PL/SQLに対して構文上の特別な意味を持つ予約語があります。たとえば、BEGINENDは予約語です。一般に、予約語は区別しやすくするために大文字で書かれています。

予約語を再定義しようとするとコンパイル・エラーが発生します。ただし、識別子の中に予約語を埋め込むことはできます。次に例を示します。

DECLARE
-- end BOOLEAN; the use of "end" is not allowed; causes compilation error
   end_of_game BOOLEAN;  -- allowed

予約語の他に、PL/SQLで特別な意味を持つキーワードがあります。PL/SQLのキーワードを識別子に使用することはできますが、お薦めしません。PL/SQLの予約語とキーワードのリストは、表D-1「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

Eは、10の累乗を意味します。次の例で示すように、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-1301.0E126(ただし1.0E126を含まない)の範囲にすることができます。リテラルは、0の場合もあります。例2-1を参照してください。有効範囲外の結果の詳細は、「NUMBERデータ型」を参照してください。

例2-1    NUMBERリテラル

DECLARE
  n NUMBER; -- declare n of NUMBER datatype
BEGIN
  n :=  -9.999999E-130;  -- valid
  n := 9.999E125; -- valid
--  n := 10.0E125; -- invalid, "numeric overflow or underflow"
END;
/

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

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

DECLARE
   x BINARY_FLOAT := sqrt(2.0f); -- single-precision floating-point number
   y BINARY_DOUBLE := sqrt(2.0d); -- double-precision floating-point number
BEGIN
   NULL;
END;
/

文字リテラル

文字リテラルは引用符(アポストロフィ)で囲まれた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.'

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

-- q'!...!' notation allows the of use single quotes
-- inside the 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を付けます。

where_clause := nq'#where col_value like '%é'#';

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

ブール・リテラル

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

日時リテラル

日時リテラルには、データ型に応じて様々な形式があります。次に例を示します。

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

DECLARE
   d1 DATE := DATE '1998-12-25';
   t1 TIMESTAMP := TIMESTAMP '1997-10-22 13:01:01';
   t2 TIMESTAMP WITH TIME ZONE := TIMESTAMP '1997-01-31 09:26:56.66 +02:00';
-- Three years and two months
-- For greater precision, we would use the day-to-second interval
   i1 INTERVAL YEAR TO MONTH := INTERVAL '3-2' YEAR TO MONTH;
-- Five days, four hours, three minutes, two and 1/100 seconds
   i2 INTERVAL DAY TO SECOND := INTERVAL '5 04:03:02.01' DAY TO SECOND;

特定の時間隔値がYEAR TO MONTHであるかDAY TO SECONDであるかも指定できます。たとえば、current_timestamp - current_timestampでは、デフォルトでINTERVAL DAY TO SECOND型の値が生成されます。時間隔の型は、次の形式で指定できます。

日付および時刻型の構文の詳細は、『Oracle Database SQLリファレンス』を参照してください。日付/時刻算術の実行例は、『Oracle Databaseアプリケーション開発者ガイド-基礎編』を参照してください。

コメント

PL/SQLコンパイラはコメントを無視しますが、ユーザーはコメントを無視しないでください。プログラムにコメントを付け加えると、わかりやすくなり理解に役立ちます。一般に、コメントは各コード・セグメントの目的や使用方法を説明するために使用します。PL/SQLでは、単一行コメントと複数行コメントの2種類のコメント・スタイルがサポートされています。

単一行コメント

単一行コメントは、行の中の任意の位置にある二重ハイフン(--)から始まり、その行の終わりまで続きます。次に例を示します。

例2-4    単一行コメントの使用

DECLARE
   howmany    NUMBER;
   num_tables NUMBER;
BEGIN
-- begin processing
   SELECT COUNT(*) INTO howmany FROM USER_OBJECTS
      WHERE OBJECT_TYPE = 'TABLE'; -- Check number of tables
   num_tables := howmany;          -- Compute some other value
END;
/

コメントは、行の末尾であれば文の途中でも使用できることに注意してください。

プログラムのテストやデバッグのときに、コード中の1行を無効にする場合があります。次の例では、行をコメントにすることによってその行を無効にする方法を示します。

-- DELETE FROM employees WHERE comm_pct IS NULL;

複数行コメント

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

例2-5    複数行コメントの使用

DECLARE
   some_condition BOOLEAN;
   pi NUMBER := 3.1415926; 
   radius NUMBER := 15; 
   area NUMBER;
BEGIN
  /* Perform some simple tests and assignments */
  IF 2 + 2 = 4 THEN
    some_condition := TRUE; /* We expect this THEN to always be performed */
  END IF;
  /* The following line computes the area of a circle using pi, which is the
     ratio between the circumference and diameter. After the area is computed,
     the result is displayed. */
  area := pi * radius**2;
  DBMS_OUTPUT.PUT_LINE('The area is: ' || TO_CHAR(area));
END;
/

コメントの制限

コメントはネストできません。また、Oracleプリコンパイラ・プログラムが処理するPL/SQLブロックの中では、単一行コメントは使用できません。これは、行の終わりを示す文字が無視され、単一行コメントが行の終わりでなくブロックの終わりまで続いてしまうためです。この場合、かわりに/* */表記法を使用します。

宣言

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

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

次に例を示します。

DECLARE
   birthday  DATE;
   emp_count SMALLINT := 0;

1つ目の宣言で、DATE型の変数の名前を決めています。2つ目の宣言で、SMALLINT型の変数の名前を決め、代入演算子を使用して変数に初期値0を代入しています。

代入演算子の後に続く式は複雑なものでもかまいません。また、事前に初期化されている変数を参照することもできます。

DECLARE
   pi     REAL := 3.14159;
   radius REAL := 1;
   area   REAL := pi * radius**2;

変数はデフォルトでNULLに初期化されます。そのため、変数宣言に「:= NULL」を含めると冗長になります。

定数

定数を宣言するには、型指定子の前にキーワードCONSTANTが必要です。次の宣言では、REAL型の定数の名前を決め、定数に変更不可能な値5000を代入しています。定数は、宣言の中で初期化する必要があります。それ以外の場合は、コンパイル・エラーが発生します。

DECLARE
   credit_limit CONSTANT REAL := 5000.00;
   max_days_in_year CONSTANT INTEGER := 366;
   urban_legend CONSTANT BOOLEAN := FALSE;

DEFAULTの使用

変数の初期化には、代入演算子のかわりにキーワードDEFAULTも使用できます。次に例を示します。

blood_type CHAR := 'O';

この宣言は、次のように書き換えることができます。

blood_type CHAR DEFAULT 'O';

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

hours_worked INTEGER DEFAULT 40;
employee_count INTEGER := 0;

DEFAULTを使用して、サブプログラム・パラメータ、カーソル・パラメータおよびユーザー定義レコードのフィールドを初期化することもできます。

NOT NULLの使用

宣言によって、初期値を代入する以外にNOT NULL制約を付けることもできます。

DECLARE
  acct_id INTEGER(4) NOT NULL := 9999;

NOT NULLと定義されている変数にはNULLを代入できません。NULLを代入しようとすると、PL/SQLは事前定義の例外VALUE_ERRORを呼び出します。

NOT NULL制約の後に初期化句を続ける必要があります。

PL/SQLでは、サブタイプNATURALNPOSITIVENは、あらかじめNOT NULLとして定義されています。これらの型の変数を宣言する場合は、NOT NULL制約を省略できますが、初期化句を含める必要があります。

%TYPE属性の使用

%TYPE属性は、変数またはデータベース列のデータ型を与えます。例2-6に示すように、%TYPEで宣言した変数は、変数のデータ型の他にデフォルト値と制約を継承します。

例2-6    変数のデータ型を持つ%TYPEの使用

DECLARE
  credit PLS_INTEGER RANGE 1000..25000;
  debit  credit%TYPE;
  v_name VARCHAR2(20);
  name VARCHAR2(20) NOT NULL := 'JoHn SmItH';
-- If we increase the length of NAME, the other variables become longer also
  upper_name name%TYPE := UPPER(name);
  lower_name name%TYPE := LOWER(name);
  init_name name%TYPE := INITCAP(name);
BEGIN
-- display inherited default values
  DBMS_OUTPUT.PUT_LINE('name: ' || name || ' upper_name: ' || upper_name 
          || ' lower_name: ' || lower_name || ' init_name: ' || init_name);
-- lower_name := 'jonathan henry smithson'; invalid, character string is too long
-- lower_name := NULL; invalid, NOT NULL CONSTRAINT
-- debit := 50000; invalid, value out of range
END;
/

%TYPE属性を使用して宣言された変数は、データ型指定子を使用して宣言された変数と同じように扱われます。たとえば前述の宣言では、PL/SQLはdebitPLS_INTEGER型の変数として扱います。%TYPE属性を使用した宣言には、初期化句も含めることができます。

%TYPE属性は、データベース列を参照する変数を宣言する場合に特に便利です。次の例のように、表や列を参照したり、所有者、表、列を参照することができます。

DECLARE
-- If the length of the column ever changes, this code
-- will use the new length automatically.
   the_trigger user_triggers.trigger_name%TYPE;

table_name.column_name.%TYPEを使用して変数を宣言する場合、実際のデータ型、および精度、位取り、長さなどの属性を知っておく必要はありません。列のデータベース定義が変更された場合でも、変数のデータ型は実行時にそれに対応して変更されます。ただし、%TYPE変数はNOT NULL、チェック制約またはデフォルト値などの列制約を継承しません。たとえば、例2-7で、データベース列empidNOT NULLとして定義されていても、変数v_empidNULLを代入できます。

例2-7    表の列での%TYPEの使用

CREATE TABLE employees_temp (empid NUMBER(6) NOT NULL PRIMARY KEY, 
 deptid NUMBER(6) CONSTRAINT check_deptid CHECK (deptid BETWEEN 100 AND 200),
 deptname VARCHAR2(30) DEFAULT 'Sales');

DECLARE
   v_empid    employees_temp.empid%TYPE;
   v_deptid   employees_temp.deptid%TYPE;
   v_deptname employees_temp.deptname%TYPE;
BEGIN
   v_empid := NULL;  -- this works, null constraint is not inherited
-- v_empid := 10000002; -- invalid, number precision too large 
   v_deptid := 50; -- this works, check constraint is not inherited
-- the default value is not inherited in the following
   DBMS_OUTPUT.PUT_LINE('v_deptname: ' || v_deptname);
END;
/

%TYPEを使用して宣言したサブタイプによって継承される列制約の詳細は、「サブタイプの制約およびデフォルト値」を参照してください。

%ROWTYPE属性の使用

%ROWTYPE属性は、表またはビューの中の行を表すレコード型を与えます。行の中の列と、それに対応するレコード中のフィールドは、同じ名前と同じデータ型を持ちます。ただし、例2-8に示すように、%ROWTYPEレコードのフィールドはNOT NULL、チェック制約またはデフォルト値などの制約を継承しません。例3-11を参照してください。

例2-8    表の行での%ROWTYPEの使用

DECLARE
   emprec    employees_temp%ROWTYPE;
BEGIN
   emprec.empid := NULL;  -- this works, null constraint is not inherited
-- emprec.empid := 10000002; -- invalid, number precision too large
   emprec.deptid := 50; -- this works, check constraint is not inherited
-- the default value is not inherited in the following
   DBMS_OUTPUT.PUT_LINE('emprec.deptname: ' || emprec.deptname); 
END;
/

例2-9に示すように、レコードには、表から選択された行全体のデータを格納することも、カーソルまたは強い型指定のカーソル変数でフェッチされた行全体のデータを格納することもできます。

例2-9    %ROWTYPE属性の使用

DECLARE
-- %ROWTYPE can include all the columns in a table...
   emp_rec employees%ROWTYPE;
-- ...or a subset of the columns, based on a cursor.
   CURSOR c1 IS
      SELECT department_id, department_name FROM departments;
   dept_rec c1%ROWTYPE;
-- Could even make a %ROWTYPE with columns from multiple tables.
   CURSOR c2 IS
      SELECT employee_id, email, employees.manager_id, location_id
      FROM employees, departments
      WHERE employees.department_id = departments.department_id;
   join_rec c2%ROWTYPE;
BEGIN
-- We know EMP_REC can hold a row from the EMPLOYEES table.
   SELECT * INTO emp_rec FROM employees WHERE ROWNUM < 2;
-- We can refer to the fields of EMP_REC using column names
-- from the EMPLOYEES table.
   IF emp_rec.department_id = 20 AND emp_rec.last_name = 'JOHNSON' THEN
      emp_rec.salary := emp_rec.salary * 1.15;
   END IF;
END;
/

集計代入

%ROWTYPE宣言に初期化句を含めることはできませんが、レコード中のすべてのフィールドに一度に値を代入する方法があります。レコードの宣言で同じ表またはカーソルが参照されている場合は、あるレコードを別のレコードに代入できます。例2-10に、可能なレコードの代入を示します。

例2-10    %ROWTYPE宣言を使用したレコードへの値の代入

DECLARE
   dept_rec1 departments%ROWTYPE;
   dept_rec2 departments%ROWTYPE;
   CURSOR c1 IS SELECT department_id, location_id FROM departments;
   dept_rec3 c1%ROWTYPE;
BEGIN
   dept_rec1 := dept_rec2;  -- allowed
-- dept_rec2 refers to a table, dept_rec3 refers to a cursor
-- dept_rec2 := dept_rec3;  -- not allowed
END;
/

次の例に示すように、SELECT文またはFETCH文を使用して列の値のリストをレコードに代入できます。列名の順番は、CREATE TABLE文またはCREATE VIEW文で定義された順番である必要があります。

DECLARE
   dept_rec departments%ROWTYPE;
BEGIN
   SELECT * INTO dept_rec FROM departments
      WHERE department_id = 30 and ROWNUM < 2;
END;
/

ただし、レコード型のコンストラクタが存在しない場合は、代入文を使用して列の値のリストをレコードに代入できません。

エイリアシングの使用

%ROWTYPE属性と関連のあるカーソルからフェッチされた選択リスト項目は、単純名を持つ必要があります。また、選択リスト項目が式の場合は別名を持つ必要があります。例2-11では、complete_nameという別名を使用して2つの列の連結を表しています。

例2-11    列名の別名の使用

BEGIN
-- We assign an alias (complete_name) to the expression value, because
-- it has no column name.
   FOR item IN
   (  SELECT first_name || ' ' || last_name complete_name
      FROM employees WHERE ROWNUM < 11  )
   LOOP
-- Now we can refer to the field in the record using this alias.
     DBMS_OUTPUT.PUT_LINE('Employee name: ' || item.complete_name);
   END LOOP;
END;
/

宣言の制限

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

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

言語によっては、同一のデータ型の複数の変数の並びを一度に宣言できます。ただし、PL/SQLではそれができません。各変数を次のように別々に宣言する必要があります。

DECLARE
-- Multiple declarations not allowed.
-- i, j, k, l SMALLINT;
-- Instead, declare each separately.
   i SMALLINT;
   j SMALLINT;
-- To save space, you can declare more than one on a line.
   k SMALLINT; l SMALLINT;

PL/SQLのネーミング規則

定数、変数、カーソル、カーソル変数、例外、プロシージャ、ファンクション、パッケージなどのPL/SQLプログラム項目には、いずれも同じネーミング規則が適用されます。名前には単純名、修飾名、リモート名または修飾リモート名があります。たとえば、プロシージャ名raise_salaryは次のように使用できます。

raise_salary(...); -- simple
emp_actions.raise_salary(...); -- qualified
raise_salary@newyork(...); -- remote
emp_actions.raise_salary@newyork(...); -- qualified and remote

1番目の例ではプロシージャ名をそのまま使用しています。2番目の例では、プロシージャがemp_actionsという名前のパッケージに格納されているため、ドット表記法を使用して名前を修飾する必要があります。3番目の例では、プロシージャがリモート・データベースに格納されているため、リモート・アクセスのインジケータ(@)を使用してデータベース・リンクnewyorkを参照しています。4番目の例では、プロシージャ名を修飾し、データベース・リンクの参照も行っています。

シノニム

シノニムを作成し、表、順序、ビュー、スタンドアロン・サブプログラム、パッケージ、オブジェクト型などのリモート・スキーマ・オブジェクトに関する位置の透過性を提供できます。ただし、サブプログラムやパッケージの中で宣言された項目については、シノニムを作成できません。これには、定数、変数、カーソル、カーソル変数、例外およびパッケージ化されたサブプログラムが該当します。

有効範囲

同じ有効範囲の中では、宣言されたすべての識別子が他と重複しないものである必要があります。そのため、変数と定数はデータ型が異なる場合でも同じ名前を共有できません。例2-12では、2番目の宣言は誤りです。

例2-12    同じ有効範囲での識別子の重複によるエラー

DECLARE
   valid_id BOOLEAN;
   valid_id VARCHAR2(5);  -- not allowed, duplicate identifier
BEGIN
-- The error occurs when the identifier is referenced,
-- not in the declaration part.
   valid_id := FALSE; -- raises an error here
END;
/

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

大/小文字の区別

定数、変数およびパラメータの名前では、すべての識別子と同様に大/小文字が区別されません。たとえば、PL/SQLは次の名前を同じものとみなします。

例2-13    識別子の大/小文字の区別

DECLARE
   zip_code INTEGER;
   Zip_Code INTEGER;  -- duplicate identifier, despite Z/z case difference
BEGIN
   zip_code := 90120; -- raises error here because of duplicate identifiers
END;
/

名前解決

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

例2-14に示すように、重複を避けるため、ローカル変数と仮パラメータの名前に接頭辞を追加するか、ブロック・ラベルを使用して参照を修飾します。

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

CREATE TABLE employees2 AS SELECT last_name FROM employees;
<<main>>
DECLARE
   last_name VARCHAR2(10) := 'King';
   v_last_name VARCHAR2(10) := 'King';
BEGIN
-- deletes everyone, because both LAST_NAMEs refer to the column
   DELETE FROM employees2 WHERE last_name = last_name;
   DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
   ROLLBACK;
-- OK, column and variable have different names
   DELETE FROM employees2 WHERE last_name = v_last_name;
   DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
   ROLLBACK;
-- OK, block name specifies that 2nd last_name is a variable
   DELETE FROM employees2 WHERE last_name = main.last_name;
   DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows.');
   ROLLBACK;
END;
/

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

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

DECLARE
   FUNCTION dept_name (department_id IN NUMBER)
      RETURN departments.department_name%TYPE
   IS
      department_name departments.department_name%TYPE;
   BEGIN
-- DEPT_NAME.department_name specifies the local variable
-- instead of the table column
      SELECT department_name INTO dept_name.department_name
         FROM departments
         WHERE department_id = dept_name.department_id;
      RETURN department_name;
   END;
BEGIN
   FOR item IN (SELECT department_id FROM departments)
   LOOP
      DBMS_OUTPUT.PUT_LINE('Department: ' || dept_name(item.department_id));
   END LOOP;
END;
/

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

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

識別子に対する参照は、その有効範囲と可視性に従って解決されます。識別子の有効範囲とは、その識別子の参照が可能な、プログラム・ユニット(ブロック、サブプログラムまたはパッケージ)の領域です。識別子は、未修飾の名前で識別子を参照できる領域からのみ、可視の状態になっています。図2-1は、xという名前の変数の有効範囲と可視性を示します。この変数は囲みブロックで宣言されてからサブブロックで再宣言されます。

あるPL/SQLブロックで宣言された識別子は、そのブロックに対してはローカルであり、そのサブブロックすべてに対してはグローバルです。グローバル識別子がサブブロックの中で再宣言されると、両方の識別子が有効範囲内にあることになります。ただし、サブブロックの中でグローバル識別子を参照する場合は修飾名が必要になるため、可視であるのはローカル識別子のみです。

同じブロックで識別子を2度宣言できませんが、同じ識別子を2つの異なるブロックで宣言できます。識別子が表す2つの項目は区別され、一方を変更しても他方には影響がありません。ただし、あるブロックから、同じレベルの他のブロックで宣言されている識別子への参照はできません。そのような識別子は、そのブロックに対してローカルでもグローバルでもないためです。

図2-1    有効範囲と可視性


画像の説明

例2-16に、有効範囲規則を示します。あるサブブロックで宣言された識別子は、別のサブブロックで参照できないことに注意してください。これは、あるブロックと同じレベルでネストされた他のブロックで宣言された識別子を、そのブロックで参照できないためです。

例2-16    有効範囲規則

DECLARE
   a CHAR;
   b REAL;
BEGIN
   -- identifiers available here: a (CHAR), b
   DECLARE
      a INTEGER;
      c REAL;
   BEGIN
     NULL; -- identifiers available here: a (INTEGER), b, c
   END;
   DECLARE
      d REAL;
   BEGIN
     NULL; -- identifiers available here: a (CHAR), b, d
   END;
   -- identifiers available here: a (CHAR), b
END;
/

グローバル識別子はサブブロックで再宣言でき、その場合はローカルな宣言が優先され、サブブロックでは、修飾名を使用しないとグローバル識別子を参照できません。例2-17に示すように、外側のブロックのラベルを修飾子として使用できます。

例2-17    識別子でのラベル修飾子の使用

<<outer>>
DECLARE
   birthdate DATE := '09-AUG-70';
BEGIN
   DECLARE
      birthdate DATE;
   BEGIN
      birthdate := '29-SEP-70';
      IF birthdate = outer.birthdate THEN
         DBMS_OUTPUT.PUT_LINE ('Same Birthday');
      ELSE
         DBMS_OUTPUT.PUT_LINE ('Different Birthday');
      END IF;
   END;
END;
/

また、例2-18に示すように、外側のサブプログラムの名前を修飾子として使用できます。

例2-18    識別子でのサブプログラム修飾子の使用

CREATE OR REPLACE PROCEDURE check_credit(limit NUMBER) AS
   rating NUMBER := 3;
   FUNCTION check_rating RETURN BOOLEAN IS
      rating        NUMBER := 1;
      over_limit    BOOLEAN;
   BEGIN
     IF check_credit.rating <= limit THEN
       over_limit := FALSE;
     ELSE
       rating := limit;
       over_limit := TRUE;
     END IF;
     RETURN over_limit;
   END check_rating;
BEGIN
   IF check_rating THEN
     DBMS_OUTPUT.PUT_LINE( 'Credit rating over limit (' || TO_CHAR(limit) 
                           || ').' || ' Rating: ' || TO_CHAR(rating));
   ELSE
     DBMS_OUTPUT.PUT_LINE( 'Credit rating OK. ' || 'Rating: ' 
                           || TO_CHAR(rating) );
   END IF;
END;
/

CALL check_credit(1);

ただし、同一の有効範囲内でラベルとサブプログラムを同じ名前にすることはできません。例2-19に示すように、ラベルを重複して使用しないようにしてください。

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

<<compute_ratio>>
<<another_label>>
DECLARE
   numerator   NUMBER := 22;
   denominator NUMBER := 7;
   the_ratio   NUMBER;
  BEGIN 
     <<inner_label>>
     <<another_label>>
   DECLARE
      denominator NUMBER := 0;
    BEGIN
      -- first use the denominator value = 7 from global DECLARE 
      -- to compute a rough value of pi
      the_ratio := numerator/compute_ratio.denominator;
      DBMS_OUTPUT.PUT_LINE('Ratio = ' || the_ratio);
      -- now use the local denominator value = 0 to raise an exception
      -- inner_label is not needed but used for clarification
      the_ratio := numerator/inner_label.denominator;
      DBMS_OUTPUT.PUT_LINE('Ratio = ' || the_ratio);
      -- if you use a duplicate label, you might get errors 
      -- or unpredictable results
      the_ratio := numerator/another_label.denominator;
      DBMS_OUTPUT.PUT_LINE('Ratio = ' || the_ratio);
    EXCEPTION
      WHEN ZERO_DIVIDE THEN
        DBMS_OUTPUT.PUT_LINE('Divide-by-zero error: can''t divide ' 
         || numerator || ' by ' || denominator);
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Unexpected error.');
  END inner_label;
END compute_ratio;
/

変数への値の代入

変数に値を代入する場合は、代入文を使用します。たとえば、次の文では変数bonusの古い値を上書きして、新しい値を代入します。

bonus := salary * 0.15;

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

例2-20    変数と定数の初期化

DECLARE
   counter INTEGER;
BEGIN
-- COUNTER is initially NULL, so 'COUNTER + 1' is also null.
   counter := counter + 1;
   IF counter IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('COUNTER is NULL not 1.');
   END IF;
END;
/

予期しない結果を避けるため、値を代入する前に変数を参照しないでください。代入演算子の後に続く式は、複雑なものでもかまいませんが、そのデータ型は変数のデータ型と同じか、または変数のデータ型に変換できるものである必要があります。

ブール値の代入

例2-21に示すように、ブール変数に代入できるのは、値TRUEFALSEおよびNULLのみです。関係演算子を使用して、これらのリテラル値、または比較などの式を代入できます。

例2-21    ブール値の代入

DECLARE
   done BOOLEAN; -- DONE is initially NULL
   counter NUMBER := 0;
BEGIN
   done := FALSE; -- Assign a literal value
   WHILE done != TRUE -- Compare to a literal value
   LOOP
      counter := counter + 1;
      done := (counter > 500); -- If counter > 500, DONE = TRUE
   END LOOP;
END;
/

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

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

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

DECLARE
   emp_id   employees.employee_id%TYPE := 100;
   emp_name employees.last_name%TYPE;
   wages    NUMBER(7,2);
BEGIN
   SELECT last_name, salary + (salary * nvl(commission_pct,0))
      INTO emp_name, wages FROM employees
      WHERE employee_id = emp_id;
   DBMS_OUTPUT.PUT_LINE('Employee ' || emp_name || ' might make ' || wages);
END;
/

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

PL/SQLの式および比較

式はオペランドと演算子を使用して作成します。オペランドとは、変数、定数、リテラルまたはファンクション・コールのことで、式の中の値はオペランドを使用して表現します。単純な算術式の例を次に示します。

-X / 2 + 3

否定演算子(-)のような単項演算子は、1つのオペランドに対して作用します。除算演算子(/)のようなバイナリ演算子は、2つのオペランドに対して作用します。PL/SQLには3項演算子はありません。

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

演算子の優先順位

式の中の演算は、優先順位に応じて特定の順序で実行されます。表2-2に、デフォルトでの演算の順序を上から順に示します。

表2-2    演算の順序 
演算子  演算 

** 

指数 

+, - 

恒等、否定 

*, / 

乗算、除算 

+, -, || 

加算、減算、連結 

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

比較 

NOT 

論理否定 

AND 

論理積 

OR 

論理和 

優先順位が高い演算子が先に適用されます。たとえば、次の2つの式の結果はどちらも8になります。これは、除算が加算よりも優先順位が高いためです。同じ優先順位の演算子は、特に順序を考慮せずに適用されます。

5 + 12 / 4
12 / 4 + 5

カッコを使用すると、評価の順序を制御できます。たとえば、次の式ではカッコで演算子のデフォルトの優先順位が上書きされるため、式の結果は11ではなく7になります。

(8 + 6) / 2

次の例では、最も深くネストされた副式が必ず最初に評価されるため、除算の前に減算が実行されます。

100 + (20 / 5 + (7 - 3))

次の例のように、カッコが不要な場合でも、わかりやすくするために自由にカッコを使用できます。

(salary * 0.05) + (commission * 0.25)

論理演算子

論理演算子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 

真理値表からわかるように、ANDは、オペランドの両方がTRUEの場合にのみTRUEを戻します。一方、ORは、オペランドの片方がTRUEならばTRUEを戻します。NOTはオペランドの反対の値(論理否定)を戻します。たとえば、NOT TRUEFALSEを戻します。

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

評価の順序

カッコを使用して評価の順序を指定しない場合は、演算子の優先順位によって順序が決定されます。次の式を比べてみてください。

NOT (valid AND done)  |  NOT valid AND done

ブール変数validdoneがどちらも値FALSEを持つ場合、1番目の式の結果はTRUEになります。ただし、2番目の式ではNOTANDより優先されるため、結果はFALSEになります。したがって、2番目の式は次の式と等価になります。

(NOT valid) AND done

次の例では、validの値がFALSEである場合、doneの値とは関係なく式全体の結果がFALSEになることに注意してください。

valid AND done

同様に、次の例では、validの値がTRUEである場合に、doneの値とは関係なく式全体の結果がTRUEになります。

valid OR done

短絡評価

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

例2-23    短絡評価

DECLARE
   on_hand  INTEGER := 0;
   on_order INTEGER := 100;
BEGIN
-- Does not cause divide-by-zero error; evaluation stops after first expression
   IF (on_hand = 0) OR ((on_order / on_hand) < 5) THEN
      DBMS_OUTPUT.PUT_LINE('On hand quantity is zero.');
   END IF;
END;
/

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

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

比較演算子

比較演算子は式と式を比較します。結果は常にTRUE、FALSE、NULLのいずれかです。比較演算子は、一般に、SQL DML文のWHERE句と、条件制御文の中で使用します。例2-24に、異なる型の比較の例を示します。

例2-24    比較演算子の使用

DECLARE
   PROCEDURE assert(assertion VARCHAR2, truth BOOLEAN)
   IS
   BEGIN
      IF truth IS NULL THEN
         DBMS_OUTPUT.PUT_LINE('Assertion ' || assertion || ' is unknown (NULL)');
      ELSIF truth = TRUE THEN
         DBMS_OUTPUT.PUT_LINE('Assertion ' || assertion || ' is TRUE');
      ELSE
         DBMS_OUTPUT.PUT_LINE('Assertion ' || assertion || ' is FALSE');
      END IF;
   END;
BEGIN
   assert('2 + 2 = 4', 2 + 2 = 4);
   assert('10 > 1', 10 > 1);
   assert('10 <= 1', 10 <= 1);
   assert('5 BETWEEN 1 AND 10', 5 BETWEEN 1 AND 10);
   assert('NULL != 0', NULL != 0);
   assert('3 IN (1,3,5)', 3 IN (1,3,5));
   assert('''A'' < ''Z''', 'A' < 'Z');
   assert('''baseball'' LIKE ''%all%''', 'baseball' LIKE '%all%');
   assert('''suit'' || ''case'' = ''suitcase''', 'suit' || 'case' = 'suitcase');
END;
/

関係演算子

次の表に、関係演算子とその意味を示します。

演算子  意味 

= 

等しい 

<>, !=, ~=, ^= 

等しくない 

< 

より小さい 

> 

より大きい 

<= 

より小さいか、等しい 

>= 

より大きいか、等しい 

IS NULL演算子

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

IF variable IS NULL THEN ...

LIKE演算子

LIKE演算子を使用すると、文字、文字列またはCLOB値をパターンと比較できます。大/小文字が区別されます。LIKEは、パターンが一致すればブール値TRUEを、一致しなければFALSEを戻します。

LIKEを使用してパターンを比較するために、ワイルドカードと呼ばれる2つの特殊な目的の文字を使用できます。アンダースコア(_)は1つの文字を表します。パーセント記号(%)は0(ゼロ)個以上の文字を表します。たとえば、last_nameの値が'JOHNSON'の場合、次の式はTRUEになります。

last_name LIKE 'J%S_N'

パーセント記号やアンダースコアを検索するには、エスケープ文字を定義して、パーセント記号またはアンダースコアの前にそのエスケープ文字を挿入します。次の例では、バックスラッシュをエスケープ文字として使用しているため、文字列中のパーセント記号はワイルドカードとしての役割は果たしません。

IF sale_sign LIKE '50\% off!'ESCAPE '\' THEN...

BETWEEN演算子

BETWEEN演算子は、ある値が、指定された範囲に含まれているかどうかをテストします。つまり、「下限以上、上限以下」という意味を持ちます。たとえば、次の式はFALSEです。

45 BETWEEN 38 AND 44

IN演算子

IN演算子は、セット・メンバーシップを調べます。集合のいずれかのメンバーと等しいかどうかがテストされます。集合にはNULLが含まれていてもかまいませんが、NULLは無視されます。たとえば、次の式は、値が集合に含まれるかどうかを調べます。

letter IN ('a','b','c')

この条件を反転する場合は注意が必要です。次の形式の式について考えます。

value NOT IN set

この式では、集合にNULLが含まれているとFALSEになります。

連結演算子

連結演算子(||)は、文字列(CHARVARCHAR2CLOBまたはそれと同等のUnicodeで使用可能な型)を他の文字列に連結します。使用例を次に示します。

'suit' || 'case'

これは、次の行を戻します。

'suitcase'

両方のオペランドがデータ型CHARを持つ場合、連結演算子はCHAR型の値を戻します。一方のオペランドがCLOB値を持つ場合、連結演算子は一時的なCLOBを戻します。それ以外の場合は、VARCHAR2型の値を戻します。

ブール式

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

SQL文の中でブール式を使用して、表の中の文が影響を与える列を指定できます。プロシージャ文では、条件制御の基盤としてブール式が使用されます。ブール式には、算術式、文字式および日付式の3種類があります。

ブール算術式

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

number1 := 75;
number2 := 70;

次の式はTRUEになります。

number1 > number2

ブール文字式

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

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

次の式はTRUEになります。

string1 > string2

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

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

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

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

ブール日付式

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

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

次の式はTRUEになります。

date1 > date2

PL/SQLブール式のガイドライン

一般に、実数を比較して等しいかどうかを判定することはお薦めしません。実数は近似値として格納されます。たとえば、次のような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;
/

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

100 < tax < 500 -- 無効

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

(100 < tax) AND (tax < 500)

ブール変数はそれ自身がTRUEまたはFALSEです。変数をリテラル値のTRUEFALSEと比較するのではなく、単に変数を条件テストに使用できます。例2-25では、ループはすべて等価です。

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

DECLARE
   done BOOLEAN ;
BEGIN
-- Each WHILE loop is equivalent
   done := FALSE;
   WHILE done = FALSE
   LOOP
      done := TRUE;
   END LOOP;
   done := FALSE;
   WHILE NOT (done = TRUE)
   LOOP
      done := TRUE;
   END LOOP;
   done := FALSE;
   WHILE NOT done
   LOOP
      done := TRUE;
   END LOOP;
END;
/

CLOB値を比較演算子またはLIKEBETWEENなどのファンクションとともに使用すると、一時的なLOBが作成されます。一時表領域がこのような一時的なLOBを処理できる大きさかどうかを確認する必要があります。

CASE式

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

単純なCASE式

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

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

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

DECLARE
   grade CHAR(1) := 'B';
   appraisal VARCHAR2(20);
BEGIN
   appraisal :=
      CASE grade
         WHEN 'A' THEN 'Excellent'
         WHEN 'B' THEN 'Very Good'
         WHEN 'C' THEN 'Good'
         WHEN 'D' THEN 'Fair'
         WHEN 'F' THEN 'Poor'
         ELSE 'No such grade'
      END;
   DBMS_OUTPUT.PUT_LINE('Grade ' || grade || ' is ' || appraisal);
END;
/

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

検索CASE式

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

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

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

DECLARE
   grade CHAR(1) := 'B';
   appraisal VARCHAR2(120);
   id NUMBER := 8429862;
   attendance NUMBER := 150;
   min_days CONSTANT NUMBER := 200;
FUNCTION attends_this_school(id NUMBER) RETURN BOOLEAN IS
   BEGIN RETURN TRUE; END;
BEGIN
   appraisal :=
      CASE
         WHEN attends_this_school(id) = FALSE THEN 'N/A - Student not enrolled'
-- Have to test this condition early to detect good students with bad attendance
         WHEN grade = 'F' OR attendance < min_days 
            THEN 'Poor (poor performance or bad attendance)'
         WHEN grade = 'A' THEN 'Excellent'
         WHEN grade = 'B' THEN 'Very Good'
         WHEN grade = 'C' THEN 'Good'
         WHEN grade = 'D' THEN 'Fair'
         ELSE 'No such grade'
      END;
   DBMS_OUTPUT.PUT_LINE('Result for student ' || id || ' is ' || appraisal);
END;
/

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

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

NULLを使用する場合は、次の規則を念頭に置くことで、問題の発生を未然に防ぐことができます。

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

例2-28    比較でのNULLの使用

DECLARE
   x NUMBER := 5;
   y NUMBER := NULL;
BEGIN
   IF x != y THEN  -- yields NULL, not TRUE
      DBMS_OUTPUT.PUT_LINE('x != y');  -- not executed
   ELSIF x = y THEN -- also yields NULL
      DBMS_OUTPUT.PUT_LINE('x = y');
   ELSE
      DBMS_OUTPUT.PUT_LINE('Can''t tell if x and y are equal or not.');
   END IF;
END;
/

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

DECLARE
   a NUMBER := NULL;
   b NUMBER := NULL;
BEGIN
   IF a = b THEN  -- yields NULL, not TRUE
      DBMS_OUTPUT.PUT_LINE('a = b');  -- not executed
   ELSIF a != b THEN  -- yields NULL, not TRUE
      DBMS_OUTPUT.PUT_LINE('a != b');  -- not executed
   ELSE
      DBMS_OUTPUT.PUT_LINE('Can''t tell if two NULLs are equal');
   END IF;
END;
/

NULLとNOT演算子

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

IF x > y THEN high := x; ELSE high := y; END IF;
IF NOT x > y THEN high := y; ELSE high := x; END IF;

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を代入します。

DECLARE
   null_string VARCHAR2(80) := TO_CHAR('');
   address VARCHAR2(80);
   zip_code VARCHAR2(80) := SUBSTR(address, 25, 0);
   name VARCHAR2(80);
   valid BOOLEAN := (name != '');

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

IF v_string IS NULL THEN ...

NULLと連結演算子

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

'apple' || NULL || NULL || 'sauce'

これは、次の行を戻します。

'applesauce'

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

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

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

例2-29    ファンクションDECODEの使用

DECLARE
   the_manager VARCHAR2(40);
   name employees.last_name%TYPE;
BEGIN
-- NULL is a valid argument to DECODE. In this case, manager_id is null
-- and the DECODE function returns 'nobody'.
   SELECT DECODE(manager_id, NULL, 'nobody', 'somebody'), last_name
      INTO the_manager, name FROM employees WHERE employee_id = 100;
   DBMS_OUTPUT.PUT_LINE(name || ' is managed by ' || the_manager);
END;
/

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

例2-30    ファンクションNVLの使用

DECLARE
   the_manager employees.manager_id%TYPE;
   name employees.last_name%TYPE;
BEGIN
-- NULL is a valid argument to NVL. In this case, manager_id is null
-- and the NVL function returns -1.
   SELECT NVL(manager_id, -1), last_name
      INTO the_manager, name FROM employees WHERE employee_id = 100;
   DBMS_OUTPUT.PUT_LINE(name || ' is managed by employee Id: ' || the_manager);
END;
/

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

例2-31    ファンクションREPLACEの使用

DECLARE
   string_type VARCHAR2(60);
   old_string string_type%TYPE := 'Apples and oranges';
   v_string  string_type%TYPE := 'more apples';
-- NULL is a valid argument to REPLACE, but does not match
-- anything so no replacement is done.
   new_string string_type%TYPE := REPLACE(old_string, NULL, v_string);
BEGIN
   DBMS_OUTPUT.PUT_LINE('Old string = ' || old_string);
   DBMS_OUTPUT.PUT_LINE('New string = ' || new_string);
END;
/

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

DECLARE
   string_type VARCHAR2(60);
   dashed string_type%TYPE := 'Gold-i-locks';
-- When the substitution text for REPLACE is NULL,
-- the text being replaced is deleted.
   name   string_type%TYPE := REPLACE(dashed, '-', NULL);
BEGIN
   DBMS_OUTPUT.PUT_LINE('Dashed name    = ' || dashed);
   DBMS_OUTPUT.PUT_LINE('Dashes removed = ' || name);
END;
/

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

条件付きコンパイル

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

「条件付きコンパイル」の新機能の説明を参照してください。ビジネスユースの事例および実践的な適用事例については、Oracle Technology NetworkのWebサイト(http://www.oracle.com/technology/tech/pl_sql/)を参照してください。

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

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

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


注意:

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


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

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

preprocessor_control_token ::= $plsql_identifier

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

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

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

$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-33を参照してください。

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

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

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-34を参照してください。

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

この項では、事前定義され、条件式で使用できる問合せディレクティブ名について説明します。このような問合せディレクティブ名には、次のものが含まれます。

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

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

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

静的なブール式

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

静的なPLS_INTEGER式

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

静的なVARCHAR2式

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

静的定数

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

static_constant CONSTANT datatype := static_expression;

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

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

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

複数のPL/SQLユニットの条件付きコンパイルを制御する静的定数を持つパッケージを使用する場合は、パッケージ仕様部のみを作成し、複数の依存性のために、そのパッケージ仕様部を条件付きコンパイルの制御専用にします。個々のユニットの条件付きコンパイルを制御するには、PLSQL_CCFLAGSに特定のフラグを設定できます。

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

例2-32    静的定数の使用

CREATE PACKAGE my_debug IS
  debug CONSTANT BOOLEAN := TRUE;
  trace CONSTANT BOOLEAN := TRUE;
END my_debug;
/
CREATE PROCEDURE my_proc1 IS
BEGIN
  $IF my_debug.debug $THEN DBMS_OUTPUT.put_line('Debugging ON'); 
  $ELSE DBMS_OUTPUT.put_line('Debugging OFF'); $END
END my_proc1;
/
CREATE PROCEDURE my_proc2 IS
BEGIN
  $IF my_debug.trace $THEN DBMS_OUTPUT.put_line('Tracing ON'); 
  $ELSE DBMS_OUTPUT.put_line('Tracing OFF'); $END
END my_proc2;
/

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

PLSQL_CCFLAGS初期化パラメータの設定

動的PLSQL_CCFLAGS初期化パラメータに、関連した値を持つフラグ名を設定し、PL/SQLユニットの条件付きコンパイルを制御することができます。たとえば、例2-34に示すように、PLSQL_CCFLAGS初期化パラメータをALTER SESSIONで動的に設定し、PL/SQLユニットのデバッグ機能とトレース機能を有効にできます。

また、例2-35に示すように、SQLのALTER PROCEDURE文を使用して、特定のPL/SQLユニットの条件付きコンパイルを独立して制御するように、PLSQL_CCFLAGS初期化パラメータを設定することもできます。

フラグ名は、予約語やキーワードなどの、引用されていない任意のPL/SQL識別子に設定できます。フラグ値を明示的に設定する場合は、TRUEFALSEPLS_INTEGERまたはNULLに設定する必要があります。フラグ名およびフラグ値では大/小文字が区別されません。制限を含むPLSQL_CCFLAGS初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

DBMS_DB_VERSIONパッケージ定数の使用

DBMS_DB_VERSIONパッケージは、条件付きコンパイルの単純な選択を行う場合に役立つ定数を提供します。PLS_INTEGER定数VERSIONおよびRELEASEは、現行のOracleバージョンとリリース番号を識別します。BOOLEAN定数VER_LE_9VER_LE_9_1VER_LE_9_2VER_LE_10VER_LE_10_1およびVER_LE_10_2は、そのバージョンおよびリリース以下であることを基準にして、TRUEまたはFALSEに評価されます。たとえば、Oracle 10g リリース2(10.2)の定数は、次のように評価されます。

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

例2-33    DBMS_DB_VERSION定数の使用

BEGIN
$IF DBMS_DB_VERSION.VER_LE_10_1 $THEN
  $ERROR 'unsupported database release' $END
$ELSE
  DBMS_OUTPUT.PUT_LINE ('Release ' || DBMS_DB_VERSION.VERSION || '.' ||
                        DBMS_DB_VERSION.RELEASE || ' is supported.');
  -- Note that this COMMIT syntax is newly supported in 10.2
  COMMIT WRITE IMMEDIATE NOWAIT;
$END
END;
/

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

条件付きコンパイルの例

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

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

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

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

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

CREATE PACKAGE my_pkg AS
  SUBTYPE my_real IS
    $IF DBMS_DB_VERSION.VERSION < 10 $THEN NUMBER; -- check database version
      $ELSE                                BINARY_DOUBLE;
    $END
  my_pi my_real; my_e my_real;
END my_pkg;
/

CREATE PACKAGE BODY my_pkg AS
BEGIN -- set up values for future calculations based on DB version
  $IF DBMS_DB_VERSION.VERSION < 10 $THEN
       my_pi := 3.14016408289008292431940027343666863227;
       my_e  := 2.71828182845904523536028747135266249775;
    $ELSE
       my_pi := 3.14016408289008292431940027343666863227d;
       my_e  := 2.71828182845904523536028747135266249775d;
  $END
END my_pkg;
/

CREATE PROCEDURE circle_area(radius my_pkg.my_real) IS
  my_area my_pkg.my_real;
  my_datatype VARCHAR2(30);
BEGIN
  my_area := my_pkg.my_pi * radius;
  DBMS_OUTPUT.PUT_LINE('Radius: ' || TO_CHAR(radius) 
                       || ' Area: ' || TO_CHAR(my_area) );
  $IF $$my_debug $THEN -- if my_debug is TRUE, run some debugging code
    SELECT DATA_TYPE INTO my_datatype FROM USER_ARGUMENTS 
       WHERE OBJECT_NAME = 'CIRCLE_AREA' AND ARGUMENT_NAME = 'RADIUS';
     DBMS_OUTPUT.PUT_LINE('Datatype of the RADIUS argument is: ' || my_datatype);
  $END
END;
/

my_debugTRUEを設定する場合は、例2-35に示すように、REUSE SETTINGS句があるプロシージャcircle_areaに対してのみこの変更を実行できます。

例2-35    ALTER PROCEDUREを使用してPLSQL_CCFLAGSを設定する方法

ALTER PROCEDURE circle_area COMPILE PLSQL_CCFLAGS = 'my_debug:TRUE' 
   REUSE SETTINGS;

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

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

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

CALL DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE('PACKAGE', 'HR', 'MY_PKG');

例2-34my_pkgHRアカウントを使用して10g 以上のリリースのデータベースでコンパイルされる場合、例2-36の出力は次のようになります。

PACKAGE my_pkg AS
  SUBTYPE my_real IS
 
                                       BINARY_DOUBLE;
 
  my_pi my_real; my_e my_real;
END my_pkg;

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

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

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

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

CREATE OR REPLACE PROCEDURE my_proc (
  $IF $$xxx $THEN i IN PLS_INTEGER $ELSE i IN INTEGER $END
 ) IS BEGIN NULL; END my_proc;
/
BEGIN
  :n := 1; -- プレースホルダの有効な使用
  $IF ....$THEN
    :n := 1; -- プレースホルダの無効な使用
$END

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

PL/SQLを使用して、WebアプリケーションやServer Pagesを開発できます。この項では、それらの方法を簡単に説明します。PL/SQLを使用してWebアプリケーションを作成する方法の詳細は、『Oracle Databaseアプリケーション開発者ガイド-基礎編』のPL/SQL Webツールキットを使用したアプリケーションの開発に関する項を参照してください。PL/SQLを使用してWeb Server Pages(PSP)を作成する方法の詳細は、『Oracle Databaseアプリケーション開発者ガイド-基礎編』のPL/SQL Server Pagesの開発に関する項を参照してください。

PL/SQL Webアプリケーション

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

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

PL/SQL Server Pages

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

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

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

PL/SQLの組込みファンクションのまとめ

PL/SQLには、データを操作するために役立つ多くの強力なファンクションが用意されています。組込みファンクションは、次のカテゴリに分類できます。

エラー・レポート
数値
文字
データ型変換
日付
オブジェクト参照
その他

表2-4に、各カテゴリのファンクションを示します。エラー・レポート・ファンクションの説明は、「SQLCODEファンクション」および「SQLERRMファンクション」を参照してください。その他のファンクションの説明は、『Oracle Database SQLリファレンス』を参照してください。

SQL文の中では、エラー報告ファンクションSQLCODESQLERRMを除くすべてのファンクションを使用できます。また、オブジェクト参照ファンクションDEREFREFおよびVALUEとファンクションDECODEDUMPおよびVSIZE以外であれば、すべてのファンクションをプロシージャ文で使用できます。

SQL集計関数(AVGCOUNTなど)とSQL分析関数(CORRLAGなど)はPL/SQLに組み込まれていませんが、SQL文に使用できます(ただし、プロシージャ文には使用できません)。

表2-4    組込みファンクション 
エラー  数値  文字  変換  日付  オブジェクト参照  その他 

SQLCODE

SQLERRM 

ABS

ACOS

ASIN

ATAN

ATAN2

BITAND

CEIL

COS

COSH

EXP

FLOOR

LN

LOG

MOD

POWER

REMAINDER

ROUND

SIGN

SIN

SINH

SQRT

TAN

TANH

TRUNC 

ASCII

ASCIISTR

CHR

COMPOSE

CONCAT

DECOMPOSE

INITCAP

INSTR

INSTR2

INSTR4

INSTRB

INSTRC

LENGTH

LENGTH2

LENGTH4

LENGTHB

LENGTHC

LOWER

LPAD

LTRIM

NCHR

NLS_INITCAP

NLS_LOWER

NLSSORT

NLS_UPPER

REGEXP_INSTR

REGEXP_LIKE

REGEXP_REPLACE

REGEXP_SUBSTR

REPLACE

RPAD

RTRIM

SOUNDEX

SUBSTR

SUBSTR2

SUBSTR4

SUBSTRB

SUBSTRC

TRANSLATE

TRIM

UNISTR

UPPER 

CHARTOROWID

CONVERT

HEXTORAW

RAWTOHEX

RAWTONHEX

ROWIDTOCHAR

TO_BINARY_DOUBLE

TO_BLOB

TO_BINARY_FLOAT

TO_CHAR

TO_CLOB

TO_DATE

TO_MULTI_BYTE

TO_NCHAR

TO_NCLOB

TO_NUMBER

TO_SINGLE_BYTE 

ADD_MONTHS

CURRENT_DATE

CURRENT_TIME

CURRENT_TIMESTAMP

DBTIMEZONE

EXTRACT

FROM_TZ

LAST_DAY

LOCALTIMESTAMP

MONTHS_BETWEEN

NEW_TIME

NEXT_DAY

NUMTODSINTERVAL

NUMTOYMINTERVAL

ROUND

SCN_TO_TIMESTAMP

SESSIONTIMEZONE

SYS_EXTRACT_UTC

SYSDATE

SYSTIMESTAMP

TIMESTAMP_TO_SCN

TO_DSINTERVAL

TO_TIME

TO_TIME_TZ

TO_TIMESTAMP

TO_TIMESTAMP_TZ

TO_YMINTERVAL

TRUNC

TZ_OFFSET 

DEREF

REF

TREAT

VALUE 

BFILENAME

COALESCE

DECODE

DUMP

EMPTY_BLOB

EMPTY_CLOB

GREATEST

LEAST

NANVL

NLS_CHARSET_DECL_LEN

NLS_CHARSET_ID

NLS_CHARSET_NAME

NULLIF

NVL

SYS_CONTEXT

SYS_GUID

UID

USER

USERENV

VSIZE 


戻る 次へ
Oracle
Copyright © 2005 Oracle Corporation.

All Rights Reserved.
目次
目次
索引
索引