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
カーソルは、使用する前に宣言されている必要があります。それには 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 文にアニメーションブレークポイントが生成されます。
オブジェクト指向 (OO) プログラムでは、データ項目を宣言することが許されている場所であればどこにでも、カーソルを宣言することができます。カーソルは、開かれるカーソルを含むオブジェクトにとってはローカルになるため、同一オブジェクトの 2 つのインスタンスが "同じ" カーソルを開いたとしても、それぞれが別のカーソルのインスタンスを得ることになります。
最初のメソッドでカーソルを開き、2 つ目のメソッドでデータを取り出し、さらに 3 つ目のメソッドで閉じるということも可能ですが、そのためにはカーソルを OBJECT-STORAGE SECTION で宣言する必要があります。
備考 :
COBSQL
宣言されたカーソルは、使用する前に開いておく必要があります。それには OPEN 文が使用されます。次の例を参照してください。
EXEC SQL OPEN Cur1 END-EXEC
DECLARE CURSOR 文でパラメータマーカを含んだ準備された文を参照する場合には、対応する OPEN 文でホスト変数、または SQLDA 構造体の名前を指定することによって、パラメータマーカに値を供給する必要があります。次の例を参照してください。
EXEC SQL OPEN Cur2 USING :last-name END-EXEC
OPEN 文の実行時に SQLDA データ構造体を使用する場合には、データ型、データ長、およびアドレスの各フィールドに適切なデータが含まれている必要があります。
COBSQL
カーソルが開かれると、データベースからデータを引き出すために使用することができます。それには 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』を参照してください。
アプリケーションがカーソルの使用を終えたら、CLOSE 文を使用してカーソルを閉じる必要があります。次の例を参照してください。
EXEC SQL CLOSE Cur1 END-EXEC
通常、カーソルが閉じられると、データやテーブルに適用されたあらゆるロックが解除されます。ただし、トランザクション中にカーソルを閉じた場合には、ロックは解除されません。
COBSQL
ここで説明するカーソルオプションに関する情報は、OpenEQSL にのみ適用されます。
次の埋め込み型 SQL 文を使用して、カーソルの動作方法やパフォーマンスを調整することが可能です。
SET SCROLLOPTION 文により、カーソルの結果セットの行メンバーシップが選択されます。
同時アクセスが発生する場合は、ある種の管理を行っていないと、すぐにデータが信頼性の低いものになってしまいます。並行性管理を有効にするには、カーソルを開く前に SET CONCURRENCY 文を使用します。
備考 : SET SCROLLOPTION および SET CONCURRENCY は、拡張 SQL の構文であり、すべての ODBC ドライバによってサポートされているわけではありません。
特定の行位置での 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 句を含める必要があります。
カーソルは大量のデータを処理するときには非常に役立つものですが、使用するにあたって心に留めておくべきことがいくつもあります。そのおもなものは、データの並行性、一貫性、および整合性です。
データの一貫性を保証するために、データベースサーバは異なるロッキング方法を実装することが可能です。ある種のデータアクセスでは全くロックは要求されず、別の場合には共用ロックや排他ロックが要求されます。共用ロックでは、他のプロセスはデータにアクセスすることは可能ですが、更新はできません。また、排他ロックでは、他のプロセスはデータにまったくアクセスすることができません。
カーソルの使用には、3 つの分離レベルがあり、それらのレベルに従って、カーソルによる読み込みおよびロックが可能なデータが管理されます。
レベル 0 では、読み込み専用のカーソルのみが使用可能です。レベル 0 では、カーソル行をロックすることはありませんが、コミットされていないデータを読み込むことは可能です。ただし、コミットされていないデータを読むのは危険です (ロールバック操作によって、データが元の状態にリセットされてしまう可能性があるためです)。通常、この操作は「ダーティー読み出し」と呼ばれています。すべてのデータベースがダーティー読み出しを許可しているわけではありません。
レベル 1 では、読み込み専用、または更新可能カーソルのみが使用可能です。レベル 1 になると、FOR UPDATE 句を使用しないかぎり、データには共用ロックが適用されています。FOR UPDATE 句が使用される場合は、データに排他ロックが適用されます。カーソルを閉じると、ロックは解除されます。FOR UPDATE 句のない標準的なカーソルの場合、通常はレベル 1 であり、共用ロックが使用されています。
レベル 3 のカーソルはトランザクションで使用されます。カーソルを閉じるときではなく、トランザクションが終わるときにロックが解除されます。レベル 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.