第 4 章 : カーソル

SELECT 文の実行結果として 1 個以上の行 (結果セット) が返されるコードを書く場合には、カーソルを宣言して使用する必要があります。

カーソルとは、結果セットの中から特定の位置にあるデータの行を一時点に 1 つずつ取り出し、それに対する更新や削除を実行できるようにするものです。カーソルと呼ばれるのは、それが結果セットにおける現在位置を示すためであり、画面上で現在位置を表わすカーソルと同じです。

次の例では、SELECT 文は DECLARE CURSOR 文カーソルにより Cursor1 と関連付けられています。また次にそのカーソルは OPEN 文で開かれています。このときに、SELECT 文が実行されます。さらに FETCH 文により、列 au_fname および au_lname から現在の行のデータが取り出され、ホスト変数、first_name および last_name にそのデータが置かれます。データが使用できなくなるまで FETCH 文でプログラムが繰り返し実行されます。最後にカーソルが閉じられます。

EXEC SQL DECLARE Cursor1 CURSOR FOR
   SELECT au_fname, au_lname FROM authors
END-EXEC
...
EXEC SQL
   OPEN Cursor1
END-EXEC
...
perform until sqlcode not = zero
   EXEC SQL
      FETCH Cursor1 INTO :first_name,:last_name
   END-EXEC
      display first_name, last_name
end-perform
...
EXEC SQL
   CLOSE Cursor1
END-EXEC

4.1 カーソルの宣言

カーソルは、使用する前に宣言されている必要があります。それには DECLARE CURSOR 文が使用され、そこにカーソルの名前と SELECT 文、または準備された SELECT 文の名前を指定します。

カーソル名は、接続するデータベースの命名規則に従う必要があります。たとえば、あるデータベースではカーソル名にハイフンを使用することは許されていません。

EXEC SQL
   DECLARE Cur1 CURSOR FOR
      SELECT first_name FROM employee 
          WHERE last_name = :last-name
END-EXEC

この例では、入力ホスト変数 (:last-name) を使用した SELECT 文が指定されています。カーソルの OPEN 文が実行されると、入力ホスト変数の値が読み込まれ、SELECT 文が実行されます。

EXEC SQL
   DECLARE Cur2 CURSOR FOR stmt1
END-EXEC
...
move "SELECT first_name FROM emp WHERE last_name=?" to prep.
EXEC SQL
   PREPARE stmt1 FROM :prep
END-EXEC
...
EXEC SQL
   OPEN Cur2 USING :last-name
END-EXEC

この例では、DECLARE CURSOR 文は準備された文 (stmt1) を参照しています。準備された SELECT 文には疑問符 (?) を含めることが可能であり、それはカーソルが開かれるときに、必要なデータが供給されるよう指示するパラメータマーカとして機能します。カーソルは、文が準備される前に宣言されている必要があります。

COBSQL
カーソルは、ユーザのプログラムの DATA DIVISION または PROCEDURE DIVISION のどちらでも宣言できます。DECLARE CURSOR 文はいかなるコードも生成しませんが、PROCEDURE DIVISION 内で宣言された場合は、COBSQL では、DECLARE CURSOR 文にアニメーションブレークポイントが生成されます。

4.1.1 オブジェクト指向の COBOL 構文

オブジェクト指向 (OO) プログラムでは、データ項目を宣言することが許されている場所であればどこにでも、カーソルを宣言することができます。カーソルは、開かれるカーソルを含むオブジェクトにとってはローカルになるため、同一オブジェクトの 2 つのインスタンスが "同じ" カーソルを開いたとしても、それぞれが別のカーソルのインスタンスを得ることになります。

最初のメソッドでカーソルを開き、2 つ目のメソッドでデータを取り出し、さらに 3 つ目のメソッドで閉じるということも可能ですが、そのためにはカーソルを OBJECT-STORAGE SECTION で宣言する必要があります。


備考 :

COBSQL


4.2 カーソルを開く操作

宣言されたカーソルは、使用する前に開いておく必要があります。それには OPEN 文が使用されます。次の例を参照してください。

EXEC SQL
   OPEN Cur1
END-EXEC

DECLARE CURSOR 文でパラメータマーカを含んだ準備された文を参照する場合には、対応する OPEN 文でホスト変数、または SQLDA 構造体の名前を指定することによって、パラメータマーカに値を供給する必要があります。次の例を参照してください。

EXEC SQL
   OPEN Cur2 USING :last-name
END-EXEC

OPEN 文の実行時に SQLDA データ構造体を使用する場合には、データ型、データ長、およびアドレスの各フィールドに適切なデータが含まれている必要があります。

COBSQL

4.3 カーソルからデータを引き出す操作

カーソルが開かれると、データベースからデータを引き出すために使用することができます。それには FETCH 文を使用します。FETCH 文により、OPEN 文によって作られた結果セットから次の行を引き出し、返されたデータを指定されたホスト変数 (または、SQLDA 構造体で指定されたアドレス) に書き込みます。次の例を参照してください。

perform until sqlcode not = 0  
   EXEC SQL
      FETCH Cur1 INTO :first_name
   END-EXEC
   DISPLAY 'First name: 'fname
   DISPLAY 'Last name : 'lname
   DISPLAY SPACES
end-perform

カーソルが結果セットの終端に達すると、SQLCA データ構造体の SQLCODE に 100 という値が返され、SQLSTATE には "02000" がセットされます。

データがカーソルから取り出されるときには、そのデータが選択されるテーブルにロックを適用することが可能です。異なるタイプのカーソルと、それが読み出すことができるロックされたデータ、およびデータに適用できるロックの種類などに関しては、カーソルオプション - OpenESQL を参照してください。

COBSQL
ORACLE のプリコンパイラの MODE 指令で、データが見つからない場合は、SQLCODE に書き込まれる値が影響を受けます。プリコンパイラでの MODE 指令に関しては、『Programmer's Guide to the ORACLE Precompilers』を参照してください。

4.4 カーソルを閉じる操作

アプリケーションがカーソルの使用を終えたら、CLOSE 文を使用してカーソルを閉じる必要があります。次の例を参照してください。

EXEC SQL
   CLOSE Cur1
END-EXEC

通常、カーソルが閉じられると、データやテーブルに適用されたあらゆるロックが解除されます。ただし、トランザクション中にカーソルを閉じた場合には、ロックは解除されません。

COBSQL

4.5 カーソルオプション - OpenESQL

ここで説明するカーソルオプションに関する情報は、OpenEQSL にのみ適用されます。

次の埋め込み型 SQL 文を使用して、カーソルの動作方法やパフォーマンスを調整することが可能です。


備考 : SET SCROLLOPTION および SET CONCURRENCY は、拡張 SQL の構文であり、すべての ODBC ドライバによってサポートされているわけではありません。


4.6 特定の行位置での UPDATE および DELETE 文

特定の行位置での UPDATE および DELETE 文は、検索条件句の代わりに、カーソルと WHERE CURRENT OF 句を同時に使用します。WHERE CURRENT OF 句では、対応するカーソルを指定します。

EXEC SQL
   UPDATE emp SET last_name = :last-name
      WHERE CURRENT OF Cur1
END-EXEC

この操作により、Cur1 カーソルを使用してデータベースから最後にフェッチされた行にある last_name が更新されます。

EXEC SQL
   DELETE emp WHERE CURRENT OF Cur1
END-EXEC

この例では、Cur1 カーソルを使用してデータベースから最後にフェッチされた行が削除されます。

OpenESQL
いくつかの ODBC ドライバでは、カーソルを使って特定の行位置での更新や削除を行う場合に、FOR UPDATE 句を含める必要があります。特定の行位置での UPDATE および DELETE は拡張 ODBC の構文であり、すべてのドライバでサポートされているわけではないことに注意してください。

COBSQL
COBSQL では、カーソルを使った特定の行位置での更新および削除を行うには、FOR UPDATE 句を含める必要があります。

4.7 カーソルの使用

カーソルは大量のデータを処理するときには非常に役立つものですが、使用するにあたって心に留めておくべきことがいくつもあります。そのおもなものは、データの並行性、一貫性、および整合性です。

データの一貫性を保証するために、データベースサーバは異なるロッキング方法を実装することが可能です。ある種のデータアクセスでは全くロックは要求されず、別の場合には共用ロックや排他ロックが要求されます。共用ロックでは、他のプロセスはデータにアクセスすることは可能ですが、更新はできません。また、排他ロックでは、他のプロセスはデータにまったくアクセスすることができません。

カーソルの使用には、3 つの分離レベルがあり、それらのレベルに従って、カーソルによる読み込みおよびロックが可能なデータが管理されます。

2 つのプロセスが同じデータを奪い合うところでは、デッドロックという問題が起きる可能性があることを覚えておいてください。古典的な例ですが、あるプロセスがデータ A をロックし、次にデータ B のロックを要求するとします。一方、別のプロセスはデータ B をロックし、データ A のロックを要求します。つまり、両方のプロセスが互いのプロセスが要求しているデータを持っていることになります。データベースサーバは、このようなケースを発見した場合に、一方の、あるいは両方のプロセスに対してエラーメッセージを送る必要があります。

COBSQL
Oracle、Sybase、および Informix のシステムでは、アプリケーションでカーソルの分離レベルをセットすることが可能になっており、附属ドキュメントでは適用するロックのタイプや動作の仕組みについて議論されています。また、データがロックされる物理レベルについても議論されています。つまり、単一行、複数行 (つまり、ページレベル)、および表全体などのそれぞれのレベルのことです。複数の表、または多くのプロセスが使っている表を走査するカーソルを使用する場合には、ロックされたデータがアクセス効率の低下につながるため、その扱いには注意が必要となります。


備考 :

COBSQL Oracle、Sybase、および Informix のシステムでは、多くの種類の句を使用してカーソルを定義することが可能です。たとえば、FOR READ ONLY、FOR UPDATE などです。これらの句を使用すると、カーソルの分離レベルやトランザクションのプロセスに巻き込まれたときの動作方法に影響がもたらされます。句の使用による影響については、ご使用のデータベースに同梱されている SQL リファレンスブックを参照してください。


Copyright © 2006 Micro Focus International Limited. All rights reserved.