rowset カーソルを使用した SQL ステートメントの実行
rowset カーソルを使用して、複数行 FETCH ステートメント、位置付け UPDATE ステートメント、および位置付け DELETE ステートメントを実行できます。
このタスクについて
- 列値の行セットを以下のいずれかのデータ域にコピーする、
複数行 FETCH ステートメント。
- プログラムで宣言されるホスト変数配列
- ストレージ・アドレスが、 取り出される列の属性とともに SQL 記述子域 (SQLDA) に入れられる、 動的割り振り配列
- いずれかの形式の複数行 FETCH ステートメントの後に、
次のステートメントを出すことができます。
- 現在行セットでの位置付け UPDATE ステートメント
- 現在行セットでの位置付け DELETE ステートメント
行セット位置付け FETCH ステートメントを使用する予定の場合は、DECLARE CURSOR ステートメント の WITH ROWSET POSITIONING 文節を使用する必要があります。
次の例は、プログラムで宣言されているホスト変数配列に 20 行を検索する FETCH ステートメントを示しています。
EXEC SQL
FETCH NEXT ROWSET FROM C1
FOR 20 ROWS
INTO :HVA-EMPNO, :HVA-LASTNAME, :HVA-SALARY :INDA-SALARY
END-EXEC.プログラムが ROWSET キーワードを指定した FETCH ステートメントを実行すると、 カーソルは、結果表の行セットの位置に置かれます。 この行セットを、現在行セット と呼びます。 それぞれのホスト変数配列の次元は、検索行数以上でなければなりません。
従業員表から取り出す列値の配列に必要なストレージを、 動的に割り振るものとします。 以下のことを行う必要があります。
- SQLDA 構造、および SQLDA を参照する変数を宣言する。
- SQLDA、および列値に必要な配列を動的に割り振る。
- 取り出す列値の SQLDA 内のフィールドを設定する。
- カーソルを開く。
- 行をフェッチする。
最初に、SQLDA 構造を宣言する必要があります。 次の SQL INCLUDE ステートメントは、 標準の SQLDA 宣言を要求します。
EXEC SQL INCLUDE SQLDA;プログラムは、SQLDA 構造を参照する変数、SQLDA 内の SQLVAR 構造、 ならびに DECIMAL 列を取り出す場合は精度および位取り用の DECLEN 構造も 宣言する必要があります。 C プログラムの場合、コードは次のようになります。
struct sqlda *sqldaptr;
struct sqlvar *varptr;
struct DECLEN {
unsigned char precision;
unsigned char scale;
};取り出す列値の SQLDA にフィールドを設定するには、SQLDA 構造にストレージを 動的に割り振っておく必要があります。 C プログラムの場合、コードは次のようになります。
sqldaptr = (struct sqlda *) malloc (3 * 44 + 16);SQLDA のサイズは SQLN * 44 + 16 です。 ここで、SQLN フィールドの値は出力列の数です。
FETCH ステートメントの SQLDA 構造には、フィールドを設定する必要があります。 列 EMPNO、LASTNAME、および SALARY を取り出すものとします。 これらの列に SQLDA フィールドを設定する C コードは、 次のようになります。
strcpy(sqldaptr->sqldaid,"SQLDA");
sqldaptr->sqldabc = 148; /* number bytes of storage allocated for the SQLDA */
sqldaptr->sqln = 3; /* number of SQLVAR occurrences */
sqldaptr->sqld = 3;
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0])); /* Point to first SQLVAR */
varptr->sqltype = 452; /* data type CHAR(6) */
varptr->sqllen = 6;
varptr->sqldata = (char *) hva1;
varptr->sqlind = (short *) inda1;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 1); /* Point to next SQLVAR */
varptr->sqltype = 448; /* data type VARCHAR(15) */
varptr->sqllen = 15;
varptr->sqldata = (char *) hva2;
varptr->sqlind = (short *) inda2;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 2); /* Point to next SQLVAR */
varptr->sqltype = 485; /* data type DECIMAL(9,2) */
((struct DECLEN *) &(varptr->sqllen))->precision = 9;
((struct DECLEN *) &(varptr->sqllen))->scale = 2;
varptr->sqldata = (char *) hva3;
varptr->sqlind = (short *) inda3;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "\x00\x00\x00\x00\x00\x01\x00\x14",varptr->sqlname.length);
SQLDA 構造には、以下のフィールドがあります。
- SQLDABC は、SQLDA に割り振るストレージのバイト数を示します。 ストレージには、16 バイトのヘッダーと、 各 SQLVAR フィールドの 44 バイトが含まれます。 値は、この例の場合、SQLN x 44 + 16、または 148 です。
- SQLN は、SQLVAR オカレンスの数 (または出力列の数) です。
- SQLD は、 FETCH ステートメントの処理時に Db2に使われる SQLDA 内の変数です。
- 各SQLVAR オカレンスは、結果表内の列の値が戻されるホスト変数配列またはバッファーを記述します。 各 SQLVAR 内では、次のようになります。
- SQLTYPE は列のデータ・タイプを示します。
- SQLLEN は列の長さを示します。 データ・タイプが DECIMAL の場合、 そのフィールドには、PRECISION と SCALE の 2 つの部分が入ります。
- SQLDATA は、列値の配列の最初のエレメントを指します。 この例の場合、プログラムは、動的変数配列 hva1、hva2、および hva3、 ならびにその標識配列 inda1、inda2、 および inda3 を割り振るものとします。
- SQLIND は、列の標識値の配列の最初のエレメントを指します。 SQLTYPE が奇数の場合、この属性は必要です。 (SQLTYPE が奇数の場合は、列に NULL 値を使用できます。)
- SQLNAME には、LENGTH と DATA の 2 つの部分があります。 LENGTH は 8です。 DATA フィールドの最初2 バイトは X'0000'です。 DATA フィールドのバイト 5 と 6 は、変数が配列であるか、または FOR n ROWS 値であるかを示すフラグです。 バイト 7 と 8 は、配列のディメンションを表す 2 バイトの 2 進整数です。
カーソルをオープンできるのは、 出力 SQLDA ですべてのフィールドが設定された後のみです。
EXEC SQL OPEN C1;OPEN ステートメントの後、 プログラムは次の行セットをフェッチします。
EXEC SQL
FETCH NEXT ROWSET FROM C1
FOR 20 ROWS
USING DESCRIPTOR :*sqldaptr; FETCH ステートメントの USING 文節は、検索される列を示す SQLDA を指します。
プログラムが FETCH ステートメントを実行して現在行セットを確立した後は、 次のいずれかの文節に位置付け UPDATE ステートメントを使用できます。
- WHERE CURRENT OF を使用して、現在行セットのすべての行を変更する
- FOR ROW n OF ROWSET を使用して、現在行セット内の行 n を変更する
WHERE CURRENT OF 文節を使用する位置付け UPDATE ステートメントの例を、 以下に示します。
EXEC SQL
UPDATE DSN8C10.EMP
SET SALARY = 50000
WHERE CURRENT OF C1
END-EXEC.UPDATE ステートメントが実行されるとき、 カーソルは、結果表の行または行セット上になければなりません。 カーソルが行に位置付けられている場合、その行が更新されます。 カーソルが行セット上にあるときは、 その行セットのすべての行が更新されます。
FOR ROW n OF ROWSET 文節を使用する位置付け UPDATE ステートメントの例を、 以下に示します。
EXEC SQL
UPDATE DSN8C10.EMP
SET SALARY = 50000
FOR CURSOR C1 FOR ROW 5 OF ROWSET
END-EXEC.UPDATE ステートメントが実行されるとき、 カーソルは、結果表の行セット上になければなりません。 現在行セット上の指定された行 (この例では、行 5) が 更新されます。
プログラムが FETCH ステートメントを実行して現在行セットを確立した後は、 次のいずれかの文節に位置付け DELETE ステートメントを使用できます。
- WHERE CURRENT OF を使用して、現在行セットのすべての行を削除する
- FOR ROW n OF ROWSET を使用して、現在行セット内の行 n を削除する
WHERE CURRENT OF 文節を使用する位置付け DELETE ステートメントの例を、 以下に示します。
EXEC SQL
DELETE FROM DSN8C10.EMP
WHERE CURRENT OF C1
END-EXEC.DELETE ステートメントが実行されるとき、 カーソルは、結果表の行または行セット上になければなりません。 カーソルが行に位置付けられている場合、その行が削除され、その結果表の次の行の前にカーソルが位置付けられます。 カーソルが行セット上にある場合は、行セットのすべての行が削除され、 カーソルは、その結果表の次の行セットの前に位置付けられます。
FOR ROW n OF ROWSET 文節を使用する位置付け DELETE ステートメントの例を、 以下に示します。
EXEC SQL
DELETE FROM DSN8C10.EMP
FOR CURSOR C1 FOR ROW 5 OF ROWSET
END-EXEC.DELETE ステートメントが実行されるとき、 カーソルは、結果表の行セット上になければなりません。 現在行セット上の指定された行が削除され、 カーソルはその行セットの位置に残ります。 削除された行 (この例では、行セットの行 5) は、 取り出しも更新もできません。