|
|
...
EXCEPTION
WHEN ZERO_DIVIDE THEN
ROLLBACK;
WHEN VALUE_ERROR THEN
INSERT INTO errors VALUES ...
COMMIT;
WHEN OTHERS THEN
NULL;
END;
| |
|
|
IF rating > 90 THEN
compute_bonus(emp_id);
ELSE
NULL;
END IF;
| |
|
|
PROCEDURE debit_account (acct_id IN INTEGER, amount IN REAL) IS
BEGIN
NULL;
END debit_account;
| |
|
|
|
|
内部的に、Oracleデータベースは、すべて「行ID」と呼ばれる
6バイトのバイナリ値を格納するROWID型の疑似列を持ちます。
行IDは行を一意に識別するので、これを使うと特定の行に最も
速くアクセスすることができます。ROWIDデータ型を使用すると
、行IDを読み取り可能な形式で格納することができます。
ROWIDはCHARのサブタイプです。このため、行IDを選択してまた
は取り出してROWID型変数に入れるときには、関数ROWIDTOCHAR
を使います。この関数は、バイナリ値を18バイトの文字列に変
換して、次の形式で戻します。
BBBBBBBB.RRRR.FFFF
BBBBBBBBはデータ・ファイル中のブロック、RRRRはブロック中
の行(最初の行が0です)、FFFFはデータ・ファイルです。これら
の数値は16進数です。たとえば、次の行IDは、7番目のデータ・
ファイルの15番目のブロックの11番目の行を指します。
0000000E.000A.0007
一般に、ROWID型変数は、カーソルが取り出した最後の行を識別
するために、UPDATE文またはDELETE文のWHERE句の中でROWID型の
疑似列と比較されます。第4章の「コミット間での取り出し」の
節に例があります。
| |
|
|
|
|
連結演算子(||)は文字列を他の文字列に連結します。たとえば、
次の式は、
'suit' || 'case'
次の値を戻します。
'suitcase'
CHAR型のオペランドだけが渡された場合、連結演算子はCHAR型の
値を戻します。CHAR型のオペランドだけではない場合は、VARCHA
R2型の値を戻します。
連結演算子はNULLオペランドを無視します。たとえば、次の式は、
'apple' || NULL || 'sauce'
次の値を戻します。
'applesauce'
| |
|
|
|
|
function DECODE (expr, search1, result1 [,search2, result2] ...
[default] )
式exprが、それぞれのsearch値と比較されます。exprがあるsearch
値と等しいと、対応するresultが戻されます。一致するものがなけ
れば、DECODEはdefault値を戻します。default値が指定されていな
ければNULLを戻します。
式exprとしては任意のデータ型が指定できますが、search値はexpr
と同じデータ型でなければなりません。戻される値はresult1と同じ
データ型に強制的に変換されます。DECODEはSQL文においてのみ使用
可能です。
関数DECODEは、先頭の引数を1つまたは複数の検索式と比較します。
検索式は結果式と対になっています。検索式や結果式はNULLの場合
があります。検索に成功すると、対応する結果が戻されます。次の
例で、ratingの値が3ならば、DECODEは値1000を戻します。
credit_limit := DECODE(rating, NULL, 1000, 'B', 2000, 'A', 4000);
| |
|
|
|
|
1) 1行コメント
1行コメントは、行の中の任意の位置にある二重ハイフン(--)
から始まり、その行の終わりまで続きます。次に例を示します。
-- begin processing
SELECT sal INTO salary FROM emp -- get current salary
WHERE empno = emp_id;
bonus := salary * 0.15; -- compute bonus amount
コメントは、行の末尾ならば文の途中でも使用できることに
注意してください。プログラムのテストやデバッグを行う際に、
コード中の1つの行を使用不能にしたい場合があります。行を
「コメントにする」方法を次の例に示します。
-- DELETE FROM emp WHERE comm IS NULL;
2) 複数行コメント
複数行コメントは、スラッシュ-アスタリスク(/*)で始まり、
アスタリスク-スラッシュ(*/)で終わります。複数の行にまた
がってもかまいません。
| |
|
|
|
|
ファンクションとは、値を計算するサブプログラムのことです。
ファンクションとプロシージャは同じような構造を持ちますが、
ファンクションの方はRETURN句を持っています。次にファンク
ションの構文を示します。
FUNCTION name [ (argument [, argument, ...]) ] RETURN datatype IS
[local declarations]
BEGIN
executable statements
[EXCEPTION
exception handlers]
END [name];
argumentには次の構文を使用します。
var_name [IN | OUT | IN OUT] datatype [{:= | DEFAULT} value]
引数宣言のデータ型指定子には制約を付けてはなりません。
プロシージャと同様に、ファンクションも仕様部と本体の2つの部
分を持ちます。ファンクションの仕様部はキーワードFUNCTIONで始
め、結果の値のデータ型を指定するRETURN句で終えます。引数宣言
はオプションです。引数を取らないファンクションではカッコを書
きません。
ファンクションの本体はキーワードISで始めキーワードENDで終え
ます。ENDの後には、オプションとしてファンクション名を続ける
ことができます。ファンクションの本体には宣言部、実行部および
オプションの例外処理部という3つの部分があります。
宣言部では、キーワードISとBEGINの間にローカル宣言を置きます。
キーワードDECLAREは使用しません。実行部では、キーワードBEGIN
とEXCEPTION(またはEND)の間に文を置きます。ファンクションの実
行部には、1つまたは複数のRETURN文が存在しなければなりません。
例外処理部では、キーワードEXCEPTIONとENDの間に例外ハンドラを
置きます。
ファンクションは式の一部として呼び出されます。たとえば、ファ
ンクションsal_okは次のようにして呼び出すことができます。
IF sal_ok(new_sal, new_title) THEN
...
END IF;
...
promotable := sal_ok(new_sal, new_title) AND (rating > 3);
いずれの場合も、ファンクション識別子は結果を戻す式の役目を持ちます。
ユーザー定義のファンクションは、プロシージャ文では呼び出せま
すが、SQL文では呼び出すことができません。たとえば、次のINSERT文
は不正です。
DECLARE
empnum INTEGER;
...
FUNCTION bonus (emp_id INTEGER) RETURN REAL IS
BEGIN ... END bonus;
BEGIN
...
INSERT INTO payroll
VALUES (empnum, ..., bonus(empnum)); -- illegal call
END;
| |
|
|
|
|
LOOP文を使用すると、一連の文を複数回実行することができます。
LOOP文には、LOOP、WHILE-LOOPおよびFOR-LOOPという3つの形式が
あります。
【LOOP】
LOOP文の最も単純な形式は、キーワードLOOPとEND LOOPで一連の
文を囲む基本(または無限)ループです。次に例を示します。
LOOP
sequence_of_statements;
END LOOP;
ループが繰り返されるごとに、一連の文が実行され、制御はルー
プの先頭に戻ります。処理の続行が望ましくない場合、または不可
能になった場合は、EXIT文を使ってループを終了させることができ
ます。ループの中では、任意の場所に1つまたは複数のEXIT文を置
くことができます。ただし、ループの外には置くことができません。
EXIT文には、EXITおよびEXIT-WHENという2つの形式があります。
【EXIT】
EXIT文はループを無条件に終了させます。EXIT文が現れると、ルー
プはただちに終了し、制御は次の文に移ります。次に例を示します。
LOOP
...
IF ... THEN
...
EXIT; -- exit loop immediately
END IF;
END LOOP;
-- control resumes here
【EXIT-WHEN 】
EXIT-WHEN文を使用すると、ループを条件に合わせて終了させること
ができます。EXIT文が現れると、WHEN句の中の条件が評価されます。
条件がTRUEに評価されると、ループは終了し、制御はループの後の文
に移ります。次に例を示します。
LOOP
FETCH c1 INTO ...
EXIT WHEN c1%NOTFOUND; -- exit loop if condition is true
...
END LOOP;
CLOSE c1;
| |
|
|
|
|
PL/SQLブロックと同様に、ループにもラベルを付けることができます。
ラベルは二重の山カッコで囲んだ未宣言の識別子で、次に示すように
LOOP文の先頭に置きます。
<<label_name>>
LOOP
sequence_of_statements;
END LOOP;
次の例のように、オプションとして、ループ文の末尾にもラベル名を
付けることができます。
<<my_loop>>
LOOP
...
END LOOP my_loop;
ラベル付きのループをネストする場合は、末尾のラベルを使って分か
りやすくすることができます。
どちらの形式のEXIT文でも、現在のループに限らず、任意の外側のル
ープも終了させることができます。終了させたい外側のループにラベ
ルを付け、そのラベルをEXIT文で使用してください。次に例を示します。
<<outer>>
LOOP
...
LOOP
...
EXIT outer WHEN ... -- exit both loops
END LOOP;
...
END LOOP outer;
ラベルを付けた外側のループが、内側のループを含めて終了されます。
| |
|
|
|
|
WHILE-LOOP文は、キーワードLOOPとEND LOOPで囲まれた一連の文
に条件を結び付けます。次に例を示します。
WHILE condition LOOP
sequence_of_statements;
END LOOP;
ループを反復する前に条件が評価されます。条件がTRUEに評価さ
れれば、一連の文が実行され、制御がループの先頭に戻ります。
条件がFALSEまたはNULLに評価されると、ループは実行されず、
制御は次の文に移ります。次に例を示します。
WHILE total <= 25000 LOOP
...
SELECT sal INTO salary FROM emp WHERE ...
total := total + salary;
END LOOP;
反復の回数は条件に依存し、ループが終了してみないと分かりませ
ん。条件はループの先頭でテストされるため、一連の文が一度も実
行されない可能性もあります。上の例でtotalの初期値が25000より
も大きいと、条件がFALSEに評価されてループは実行されません。
いくつかの言語は、条件をループの先頭ではなく末尾でテストする
LOOP UNTIL構造または REPEAT UNTIL構造を持っています。この場合、
一連の文は少なくとも一度は実行されます。PL/SQLにはこうした構
造はありませんが、次のようにすれば簡単に作ることができます。
LOOP
sequence_of_statements;
EXIT WHEN boolean_expression;
END LOOP;
| |
|
|
|
|
WHILEループの反復回数はループが終了するまでは分かりませんが、
FORループの反復回数はループに入る前から分かっています。FORル
ープは指定された整数の範囲で実行を繰り返します。範囲はキーワ
ードFORとLOOPで囲まれる「反復スキーム」の一部です。次に構文
を示します。
FOR counter IN [REVERSE] lower_bound..higher_bound LOOP
sequence_of_statements;
END LOOP;
範囲はFORループに入ったときに評価され、それ以降は再評価されま
せん。次の例に示すように、一連の文は範囲中の整数1つについて1
回実行されます。繰り返しが1回起こるごとに、ループ・カウンタが
1つ増やされます。
FOR i IN 1..3 LOOP -- assign the values 1,2,3 to i
sequence_of_statements; -- executes three times
END LOOP;
次の例のように、下限が上限と等しければ、一連の文は1回だけ実行
されます。
FOR i IN 3..3 LOOP -- assign the value 3 to i
sequence_of_statements; -- executes one time
END LOOP;
デフォルトでは、反復は下限から上限の向きに進みます。しかし、
次の例のように、キーワードREVERSEを使用すると、反復は上限から
下限の向きに進みます。繰り返しが1回起こるごとに、ループ・カウ
ンタが1つ減らされます。
FOR i IN REVERSE 1..3 LOOP -- assign the values 3,2,1 to i
sequence_of_statements; -- executes three times
END LOOP;
この場合でも、範囲の上限と下限は(降順ではなく)昇順に書きます。
FORループの中では、ループ・カウンタを定数のように参照すること
ができます。次に示すように、ループ・カウンタは式の中でも使用で
きますが、値を代入することはできません。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FOR ctr IN 1..10 LOOP
...
IF NOT finished THEN
INSERT INTO ... VALUES (ctr, ...); -- legal
factor := ctr * 2; -- legal
...
ELSE
ctr := 10; -- illegal
END IF;
END LOOP;
次に示すように、PL/SQLではループの繰り返し範囲を実行時に動的
に決定することができます。
SELECT COUNT(empno) INTO emp_count FROM emp;
FOR i IN 1..emp_count LOOP
...
END LOOP;
emp_countの値はコンパイル時には未定で、SELECT文が実行時に戻し
ます。
ループ・カウンタは、INTEGER型のローカル変数として暗黙的に宣言さ
れているので、明示的に宣言する必要はありません。次の例では、ロ
ーカル宣言がグローバル宣言を隠しています。
DECLARE
ctr INTEGER;
BEGIN
...
FOR ctr IN 1..25 LOOP
...
IF ctr > 10 THEN ... -- refers to loop counter
END LOOP;
END;
この例でグローバル変数を使用するには、次のようにラベルとピリオ
ド記号を使用する必要があります。
<<main>>
DECLARE
ctr INTEGER;
...
BEGIN
...
FOR ctr IN 1..25 LOOP
...
IF main.ctr > 10 THEN ... -- refers to global variable
END LOOP;
END main;
ネストされたFORループにも同じ有効範囲の規則が適用されます。次の
例を考えてみてください。どちらのループ・カウンタも同じ名前を持っ
ています。このため、内側のループから外側のループ・カウンタを参
照するには、次のようにラベルとピリオド記号を使用する必要があります。
<<outer>>
FOR step IN 1..25 LOOP
FOR step IN 1..10 LOOP
...
IF outer.step > 15 THEN ...
END LOOP;
END LOOP outer;
| |
|
|
|