7.2.1 複合文の形式と規則
(1) 機能
複数のSQL文をまとめて,一つのSQL文(複合文)として実行します。
(2) 形式
〔開始ラベル:〕 BEGIN 〔{SQL変数宣言;|カーソル宣言;|条件宣言;|ハンドラ宣言;}〕… 〔SQL手続き文;〕… END 〔終了ラベル〕 SQL変数宣言::=DECLARE SQL変数名〔,SQL変数名〕…データ型 〔DEFAULT句〕 DEFAULT句::=DEFAULT 〔既定値〕 条件宣言::=DECLARE 条件名 CONDITION 〔FOR SQLCODE値〕 ハンドラ宣言::=DECLARE ハンドラ種別 HANDLER FOR 条件値〔,条件値〕… ハンドラ動作 ハンドラ種別::={CONTINUE|EXIT} 条件値::={SQLERROR|NOT FOUND|条件名|SQLCODE値} ハンドラ動作::=SQL手続き文 SQLCODE値::=SQLCODE 〔VALUE〕 整数定数
(3) オペランド
(a) 〔開始ラベル〕
複合文の文ラベルを指定します。
(b) BEGIN
複合文の開始を指定します。
(c) SQL変数宣言::=DECLARE SQL変数名〔,SQL変数名〕…データ型 〔DEFAULT句〕
複合文中で使用するSQL変数を宣言します。SQL変数が割り当てられたとき,初期値としてSQL変数の既定値が設定されます。SQL変数の既定値はDEFAULT句で指定します。DEFAULT句を省略した場合,SQL変数の既定値はナル値になります。
- SQL変数名
-
宣言するSQL変数の名称を指定します。
- データ型
-
宣言するSQL変数のデータ型を指定します。
- SQL変数宣言の規則
-
-
SQL変数宣言中で宣言するSQL変数の名称には,ルーチンのパラメタ名と同じ名称は指定できません。
-
同じ複合文中に直接含まれるSQL変数宣言中で宣言するSQL変数の名称は,重複して指定できません。
-
複合文中で宣言したSQL変数は,その複合文の最初に割り当てられ,最後に解放されます。
-
SQL変数の有効範囲は,そのSQL変数が宣言されている複合文の中,及び同じ複合文の中に宣言されているハンドラ宣言のハンドラ動作の中になります。また,その複合文の中のSQL手続き文に複合文を指定した場合は,内側の複合文の中でも有効です。
-
複合文の中のSQL手続き文に複合文を指定した場合,外側の複合文の中で宣言したSQL変数と,内側の複合文の中で宣言したSQL変数が同じ名称のときは,内側の複合文の中では内側で宣言したSQL変数が有効となります。内側の複合文が終了したら,外側で宣言したSQL変数が有効となります。
-
SQL変数宣言中で宣言するSQL変数のデータ型には,BOOLEANは指定できません。
-
- DEFAULT句::=DEFAULT 〔既定値〕
-
DEFAULT句の規則については,「CREATE TABLE(表定義)」のDEFAULT句の規則を参照してください。
既定値としてCURRENT_TIMESTAMP〔(小数秒精度)〕 USING BES又はCURRENT TIMESTAMP〔(小数秒精度)〕 USING BESは指定できません。
(d) カーソル宣言
複合文中で使用するカーソルを宣言します。
- カーソル宣言の規則
-
-
同じ複合文中に直接含まれる,カーソル宣言中で宣言するカーソルの名称は,重複して指定できません。
-
複合文中で宣言したカーソルは,その複合文の最初に割り当てられ,最後に解放されます。ただし,WITH RETURN指定をして宣言したカーソルは,解放されません。
-
カーソルの有効範囲は,そのカーソルが宣言されている複合文の中,及び同じ複合文の中に宣言されているハンドラ宣言のハンドラ動作の中になります。また,その複合文の中のSQL手続き文に複合文を指定した場合は,内側の複合文の中でも有効です。
-
複合文の中のSQL手続き文に複合文を指定した場合,外側の複合文の中で宣言したカーソルと,内側の複合文の中で宣言したカーソルが同じ名称のときは,内側の複合文の中では内側で宣言したカーソルが有効となります。内側の複合文が終了したら,外側で宣言したカーソルが有効となります。
-
(e) 条件宣言::=DECLARE 条件名 CONDITION 〔FOR SQLCODE値〕
ハンドラ宣言,SIGNAL文,又はRESIGNAL文の中で使用する条件名と,それに対応するSQLCODEの値を宣言します。
- 条件名
-
宣言する条件の名称を指定します。
- FOR SQLCODE値
-
宣言する条件に対応づけるSQLCODEの値を指定します。
- 条件宣言の規則
-
-
同じ複合文中に直接含まれるほかの条件宣言に,同じ条件名を重複して指定できません。
-
条件名の有効範囲は,その条件名が宣言されている複合文の中,及び同じ複合文の中に宣言されているハンドラ宣言のハンドラ動作の中になります。また,その複合文の中のSQL手続き文に複合文を指定した場合は,内側の複合文の中でも有効です。
-
複合文の中のSQL手続き文に複合文を指定した場合,外側の複合文の中で宣言した条件名と同じ条件名を使用した条件宣言は,内側の複合文の中で宣言できません。
-
同じ複合文中に直接含まれる条件宣言を複数指定する場合,同じSQLCODE値は指定できません。
-
SIGNAL文,又はRESIGNAL文の中で使用する条件名を宣言する場合は,"FOR SQLCODE値"を省略してください。指定した場合はエラーとなります。
-
(f) ハンドラ宣言::=DECLARE ハンドラ種別 HANDLER FOR 条件値〔,条件値〕… ハンドラ動作
複合文中で例外処理をするためのハンドラを宣言します。
複合文中のSQL文を実行した結果のSQLCODE値,SIGNAL文,又はRESIGNAL文の条件名がハンドラ宣言で指定した条件値と一致すると,ハンドラが制御を受け取り,ハンドラ動作を実行します。
- ハンドラ種別::={CONTINUE|EXIT}
-
- CONTINUE
-
ハンドラ動作を実行した後に,例外を発生したSQL手続き文の次のSQL手続き文に制御を移します。ただし,例外を発生したSQL手続き文がルーチン制御SQLのIF文,又はWHILE文の場合,END IF,又はEND WHILE〔終了ラベル〕の次のSQL手続き文に制御を移します。
- EXIT
-
ハンドラ動作を実行した後に,ハンドラ宣言を指定した複合文の最後に制御を移します。
条件値::={SQLERROR|NOT FOUND|条件名|SQLCODE値}
ハンドラが有効になる条件を指定します。
- SQLERROR
-
SQLERRORが発生した場合に,ハンドラを呼び出すときに指定します。SQLERRORは,SQLCODE<0となる場合に対応しています。
- NOT FOUND
-
NOT FOUNDが発生した場合に,ハンドラを呼び出すときに指定します。NOT FOUNDは,SQLCODE=100となる場合に対応しています。
- 条件名
-
ハンドラが呼び出される条件となる条件名を指定します。
条件名は,条件宣言であらかじめ定義されていて,かつこのハンドラ宣言を有効範囲として含んでいる必要があります。
条件宣言の中で条件名に対応するSQLCODE値が定義されている場合は,SQLCODEがその値と一致したときにハンドラが呼び出されます。条件宣言の中で条件名に対応するSQLCODE値が定義されていない場合は,その条件名を指定したSIGNAL文,又はRESIGNAL文を実行したときだけハンドラが呼び出されます。
- SQLCODE値
-
ハンドラが呼び出される条件となるSQLCODEの値を指定します。
- ハンドラ動作::=SQL手続き文
-
ハンドラが呼び出されたときに実行するSQL手続き文を指定します。
- ハンドラ宣言の規則
-
-
ハンドラは,そのハンドラが宣言されている複合文の中のSQL手続き文を有効範囲とします。その複合文の中のSQL手続き文に複合文を指定した場合は,内側の複合文全体で有効となります。ただし,そのハンドラが宣言されている複合文の中の,ハンドラ宣言中のSQL手続き文は無効となります。例を次に示します。
-
ハンドラ宣言の中で,条件値にSQLERROR,又はNOT FOUNDのどちらかを指定した場合,同時にSQLCODE値,又は条件名を指定できません。
-
ハンドラ宣言の中で,同じ条件値は重複して指定できません。また,SQLCODE値と同じSQLCODEを表す条件名も指定できません。
-
同じ複合文の中に含まれるほかのハンドラ宣言に,同じ条件を表す条件値は指定できません。
-
条件値にSQLERROR,又はNOT FOUNDを指定したハンドラ宣言を一般ハンドラ宣言,それ以外は特定ハンドラ宣言とします。同じ複合文の中に,同じSQLの実行状態(異常終了,警告あり正常終了,又はデータなし)を示す条件値を指定した一般ハンドラ宣言と特定ハンドラ宣言が定義されている場合,特定ハンドラ宣言で指定したSQLCODE値に対しては,特定ハンドラ宣言だけが有効になります。
-
複合文の中のSQL手続き文に複合文を指定した場合に,外側の複合文で宣言したハンドラAと内側の複合文の中で宣言したハンドラBとで,同じSQLCODE,又は条件名を指定したときは,内側の複合文の中では内側のハンドラBが有効となります。内側の複合文が終了したら,再び外側のハンドラAが有効となります。例を次に示します。
-
ハンドラ動作が正常終了でない(SQLCODE=0以外)場合,条件を満たすほかのハンドラがあれば呼び出します。
-
ハンドラ動作開始直後は,SQLCODE=0となります。
-
(g) SQL手続き文
複合文中で実行するSQL手続き文を指定します。
(h) END〔終了ラベル〕
複合文の終了を指定します。終了ラベルには,文ラベルを指定します。
(i) SQLCODE値::=SQLCODE 〔VALUE〕 整数定数
SQLCODEの値を整数定数で指定します。
SQLCODEの値として,正常終了を表す値である0は指定できません。SQLCODE値に指定する整数定数を次の表に示します。
SQL文の実行状態 |
SQLCODEの値 |
---|---|
正常終了(警告あり) |
>0(≠100,110) |
データがない |
100 |
異常終了 |
<0 |
HiRDBで発生する可能性がある,SQLCODEに対応するメッセージを次の表に示します。
SQLCODE |
対応するメッセージID |
---|---|
-yyy |
KFPA11yyy |
-1yyy |
KFPA19yyy |
-3yyy |
KFPA18yyy |
yyy |
KFPA12yyy |
+3yyy |
KFPA13yyy |
(4) 共通規則
-
最も外側のSQL手続き文に複合文を指定して,開始ラベルを省略した場合は,そのルーチンのルーチン識別子が文ラベルとして仮定されます。また,複合文の中のSQL手続き文に複合文を指定した場合,内側の複合文に対する開始ラベルを省略したときは,文ラベルなしとして扱われます。
-
終了ラベルを指定する場合は,開始ラベルと同じ名称の文ラベルを指定してください。
-
文ラベルの有効範囲は,文ラベルを指定した複合文の開始から終了までの間です。その複合文中に含まれる,ほかの文の文ラベル,及びループ変数名と同じ名称の文ラベルは指定できません。ただし,複合文中にハンドラ宣言がある場合,そのハンドラ宣言中は除きます。同一名称の文ラベルの指定可否の例を次に示します。
AAA: BEGIN ...........................................1 DECLARE CN1 CONDITION FOR SQLCODE VALUE -800; DECLARE EXIT HANDLER FOR CN1 AAA: BEGIN .........................................2 : END AAA; AAA: BEGIN .........................................3 DECLARE CN2 CONDITION FOR SQLCODE VALUE -800; DECLARE EXIT HANDLER FOR CN2 : END AAA; : END AAA
- 〔説明〕
-
2は,1と同一名称ですが,ハンドラ宣言中のため指定できます。
3は,1と同一名称であり,ハンドラ宣言中でないため指定できません。
-
指定したSQL手続き文は,指定した順序で実行されます。
-
SQL手続きの実行中にエラーが発生した場合に,トランザクションが無効になるのは,そのエラーが暗黙的ロールバックありのときだけです。トリガ動作のSQL手続き文の実行中にエラーが発生した場合は,必ず暗黙的ロールバックとなります。
-
SQL手続き文の実行でエラーが発生した場合は,次の規則に従います。
-
暗黙的ロールバックなしのエラーが発生した場合
条件を満たすハンドラがあれば,そのハンドラの例外処理を実行します。条件を満たすハンドラがなければ,その時点でSQLルーチンの実行を終了し,エラーを返します。それ以降のSQL手続き文は実行されません。
-
暗黙的ロールバックありのエラーが発生した場合
条件を満たすハンドラがあっても,例外処理はしないで,その時点でSQLルーチン,又はトリガの実行を終了し,エラーを返します。それ以降のSQL手続き文は実行されません。
-
-
複合文,及びFOR文のネスト数は,最大255です。
-
SQL変数名,カーソル名,及び条件名に,次の名称を指定する場合は,引用符(")で名称を囲んでください。
-
CONDITION
-
EXIT
-
HANDLER
-
(5) 留意事項
-
複合文は,SQLルーチン中,及びトリガ中に指定できます。
(6) 使用例
-
在庫表(ZAIKO)の数量が,1,000個以上の商品の単価を3割引きに,0の場合はその行を削除し,そのほかの場合は単価を1割引きにする手続き(PROC1)を定義します。
CREATE PROCEDURE PROC1(OUT OUTDATA INT) BEGIN DECLARE CR1 CURSOR FOR SELECT SURYO FROM ZAIKO ; OPEN CR1 ; WHILE SQLCODE=0 DO FETCH CR1 INTO OUTDATA ; IF SQLCODE=0 THEN IF OUTDATA>=1000 THEN UPDATE ZAIKO SET TANKA = (1-0.3)*TANKA WHERE CURRENT OF CR1 ; ELSE IF OUTDATA=0 THEN DELETE FROM ZAIKO WHERE CURRENT OF CR1 ; ELSE UPDATE ZAIKO SET TANKA = (1-0.1)*TANKA WHERE CURRENT OF CR1 ; END IF ; END IF ; END; END
-
在庫表(ZAIKO)に対し,指定した商品コードの数量を更新するSQL手続き(PROC2)を定義します。
-
指定した数量が0以下である場合(手続き内で定義する条件illegal_valueになる場合)
SIGNAL文でエラーを発生させ,例外処理で出力パラメタにメッセージを設定します。また,SQL手続きの実行は終了します。
-
指定した商品コードのデータがない場合(NOT FOUNDになる場合)
例外処理で出力パラメタにメッセージを設定します。また,SQL手続き文の実行は終了します。
-
非ナル値制約ありの列をNULL値で更新しようとした場合(SQLCODE=-210になる場合)
例外処理で出力パラメタにメッセージを設定します。また,SQL手続き文の実行は継続します。
CREATE PROCEDURE PROC2(IN USCODE CHAR(4), IN USURYO INT, OUT MSG MVARCHAR(255)) BEGIN DECLARE PSURYO INT; DECLARE illegal_value CONDITION ; DECLARE EXIT HANDLER FOR illegal_value SET MSG=M'数量として無効な値です。'; DECLARE EXIT HANDLER FOR NOT FOUND SET MSG=M'指定された商品コードは登録されていません。'; DECLARE CONTINUE HANDLER FOR SQLCODE VALUE -210 SET MSG=M'非ナル値制約ありの列をNULL値で更新しようとしましたが, 無視します。'; SET MSG =''; IF USURYO<0 THEN SIGNAL illegal_value; ELSE UPDATE ZAIKO SET ZSURYO=USURYO WHERE ZSCODE=USCODE; SET MSG=MSG||M'処理が完了しました。 ' SELECT ZSURYO INTO PSURYO FROM ZAIKO WHERE ZSCODE=USCODE; SET MSG=MSG||M'現在の数量:'||NUMEDIT(PSURYO,'<999999'); END IF; END
-
-
在庫表(ZAIKO)に対し,新規の商品データを登録するSQL手続き(PROC3)を定義します。
なお,商品コード列(SCODE)は主キーであるものと仮定します。挿入するデータの商品コードが,既に登録されているデータの商品コードと重複する場合(SQLCODE=-803の場合),例外処理でロールバックをさせて,出力パラメタにメッセージを設定します。また,SQL手続き文の実行は終了します。
CREATE PROCEDURE PROC3(IN USCODE CHAR(4) , IN USNAME NCHAR(8), IN UCOL NCHAR(1), IN UTANKA INT, OUT MSG MVARCHAR(255)) BEGIN DECLARE EXIT HANDLER FOR SQLCODE VALUE -803 BEGIN ROLLBACK; SET MSG=M'重複キー違反のため,ロールバックしました。'; END; INSERT INTO ZAIKO VALUES(USCODE,USNAME,UCOL,UTANKA,0); SET MSG=M'登録が完了しました。'; END