SQLでは、カーソルは、アプリケーションプログラミング言語が一度に1行ずつクエリ結果を処理できるようにするポインタとして機能します。この記事では、背後にある概念を簡単に説明し、カーソルを宣言し、カーソルを開き、カーソルからデータを取得してから閉じる方法を示します。
SQLカーソル
リレーショナルデータベースのデータは、セットの形式で管理されます。その結果、SQL SELECTステートメントによって返されるクエリ結果は、結果セットと呼ばれます。結果セットは、1つ以上のテーブルから抽出された1つ以上の行と列の組み合わせに他なりません。結果セットをスクロールして、必要な情報を抽出できます。返されるデータ要素は、特定のアプリケーションの目的でJavaやその他のプログラミング言語によって使用されます。しかし、ここにインピーダンスの不一致の問題があります。 データベースモデルとプログラミング言語モデルの構成が異なるためです。
SQLデータベースモデルには、次の3つの主要な構成要素があります。
- 列(または属性)とそのデータ型
- 行(レコードまたはタプル)
- テーブル(レコードのコレクション)
したがって、2つのモデル間の主な不一致は次のとおりです。
- データベースモデルで使用可能な属性データ型は、プログラミング言語で使用される変数型と同じではありません。多くのホスト言語があり、それぞれが異なるデータ型を持っています。たとえば、C / C ++とJavaのデータ型は異なり、SQLデータ型も異なります。したがって、非互換性の問題を軽減するには、バインディングメカニズムが必要です。
- SQL SELECTステートメントによって返される結果は、各レコードが属性のコレクションであるレコードのマルチセットです。ホストプログラミング言語は通常、クエリによって返されるタプルの個々のデータ値を処理します。したがって、SQLクエリの結果がプログラミング言語でサポートされているデータ構造にマップされていることが不可欠です。タプルとその属性値を反復処理するには、タプルをループするメカニズムが必要です。
カーソルはイテレータ変数のように機能して、SQLクエリによって返されたタプルをループし、各タプル内の個々の値を抽出して、適切なタイプのプログラム変数にマップできます。
したがって、カーソルは、プログラミング言語がクエリ結果を一度に1レコードずつ処理できるようにするポインタとして機能します。カーソルは、一度に1行に焦点を合わせて、クエリ結果のすべての行を移動できます。次のSQLクエリについて考えてみます。
SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
上記のステートメントのクエリ結果は、生年月日が特定の月の当日に当たるすべての従業員の従業員の詳細を返します。結果には多くの行が含まれる場合がありますが、ホストアプリケーション言語は一度に1つの行を処理できます。その結果、カーソルはアプリケーションプログラミング言語内の埋め込みSQLステートメントとして宣言されます。次に、カーソルがファイルのように開かれ、クエリ結果から単一の行が抽出されます。その後、カーソルが閉じるまで順番に他の行が抽出されます。
カーソルの宣言
カーソルは変数のように宣言されます。名前が付けられ、カーソルを開き、クエリ結果を取得し、最後にカーソルを閉じるステートメントがあります。異なるSQL実装は、異なる方法でのカーソルの使用をサポートしていることに注意してください。ただし、カーソルの書き込み方法については一般的な合意があります。
SQLデータベースからデータを抽出するには、カーソルを宣言するだけでは不十分であるため、SQLステートメントを使用してカーソル機能を完全に実装する必要があります。カーソルを宣言するには、次の4つの基本的な手順があります。
カーソルの宣言: 宣言は、カーソルに名前を付け、カーソルが開いたときに呼び出されるクエリ式を割り当てることから始まります。
OPEN: openステートメントは、割り当てられたクエリ式を実行し、後続のFETCHのクエリ結果を準備します。
FETCH: データ値を変数に取得し、それをホストプログラミング言語または他の埋め込みSQLステートメントに渡すことができます。
閉じる: これ以上クエリ結果をフェッチできないようにカーソルが閉じられます。
構文は次のとおりです。
DECLARE <cursor_name> [SENSITIVE | INSENSITIVE | ASENSITIVE] [SCROLL | NO SCROLL] CURSOR [ WITH HOLD | WITHOUT HOLD] [ WITH RETURN | WITHOUT RETURN] FOR <sql_query_expression> [ ORDER BY <sort_expression>] [ FOR {READ ONLY | UPDATE [ OF <list_of_column>]}]
カーソル宣言の重要な部分は次のとおりです。
DECLARE <cursor_name> FOR <sql_query_expression>
[SENSITIVE|などのオプションパーツ鈍感| ASENSITIVE]は、カーソルが変更に敏感であるかどうか、およびそれらをクエリ結果に反映するかどうかを示します。 SENSITIVEはカーソルが変更の影響を受けることを意味し、INSENSITIVEはカーソルが影響を受けないことを意味し、ASENSITIVEは変更がカーソルに表示される場合と表示されない場合があることを意味します。指定しない場合、ASENSITIVEオプションを想定します。
オプションの[スクロール| NOSCROLL]は、カーソルのスクロール能力を定義します。指定しない場合、スクロールなしオプションと見なされます。
オプションの[WITHHOLD| WITHOUT HOLD]は、カーソルによるトランザクションがコミットされたときに、保留するか自動的に閉じるかを定義します。指定しない場合、WITHOUTHOLDオプションが維持されます。
オプションの[WITHRETURN| WITHOUT RETURN]は、カーソル結果セットを別のSQLルーチンやホスト言語などの呼び出し元に返すかどうかを決定します。指定されていない場合は、返品なしを意味します。
ORDER BY句は、指定された並べ替え手法に従って返されたクエリ結果を並べ替えるために使用されます。
UPDATEオプションは、UPDATEまたはDELETEステートメントの使用を参照します。これは、カーソルのSELECTステートメントによって返される行との関連付けです。 READ ONLYオプションを指定した場合、このような変更はできません。指定しない場合、デフォルトでUPDATEオプションが想定されます。
したがって、単純なカーソルは次のように宣言できます。
DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
MySQLのカーソル
通常、MySQLには、読み取り専用カーソルと転送専用カーソルの2種類のカーソルがあります。これらのカーソルは、MySQLストアドプロシージャに使用できます。これらのカーソルは、クエリ結果を一度に1行ずつ繰り返し、さらに処理するために変数にフェッチするのに役立ちます。複数のカーソルを宣言して、それらをループにネストすることができます。カーソルは一時テーブルを反復処理するために使用されるため、読み取り専用であることに注意してください。カーソルは通常、開くときにクエリを実行します。
MySQLのカーソルに関する問題の1つは、実行する余分なI / O操作が原因で、クエリのパフォーマンスが低下する可能性があることです。これは特に、BLOBやTEXTなどの真の大きなデータ型に当てはまります。カーソルは一時テーブルで機能するため、これらのタイプはメモリ内テーブルではサポートされていません。したがって、これらのタイプで作業している間、MySQLはディスク上に一時テーブルを作成する必要があり、それは多くのI / O操作を必要とし、ディスクのような遅いデバイスでもそれを必要とします。これが、カーソルのパフォーマンスが低下する主な理由です。
MySQLはクライアント側カーソルもサポートしていませんが、クライアントAPIは必要に応じてそれらをエミュレートできます。しかし、これは、Javaのようなプログラミング言語で配列に結果をフェッチし、代わりにそこで操作することと大差ありません。
これは、MySQLでカーソルを書き込む方法のサンプルです。
CREATE PROCEDURE 'cursor_demo'() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE id INT(11); DECLARE fn varchar(14); DECLARE ln varchar(16); DECLARE bdate date; DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date)=MONTH(CURRENT_DATE) AND DAY(birth_date)=DAY(CURRENT_DATE); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN mycursor; fetch_loop: LOOP FETCH mycursor INTO id, fn, ln, bdate; IF done THEN LEAVE fetch_loop; END IF; SELECT id, fn, ln, bdate; END LOOP; CLOSE mycursor; END
次のようにストアドプロシージャを呼び出します。
mysql> CALL cursor_demo
このプロシージャは、 employeeという名前のテーブルから行をフェッチします。 mycursor という名前のカーソルで、生年月日が現在の日と月に一致する SELECTステートメントを使用してそれらを出力するだけです。
詳細については、カーソルに関するMySQLのドキュメントを参照してください。
結論
カーソルは、SQLクエリによって返されるレコードのセットへのポインタに他なりません。ポインタは通常、一度に1つの行を指し、ループ内を移動して個々のレコードを取得できます。 SQLは通常、データオブジェクトにアクセスして作成するための直接呼び出しに使用されます。カーソルは、クライアントアプリケーションを介して促進されるSQLステートメントのアドホック実行を可能にするインタラクティブSQLの手法を提供します。カーソルのメカニズムは、SQLステートメントがC、C ++、Javaなどのホスト言語に埋め込まれているデータアクセスモデルを利用します。これは、カーソルが何から始まるのかを垣間見るだけです。さまざまな実装の特定の基準の詳細については、適切なSQLデータベースのドキュメントを参照してください。
###