私は1年間(Oracle dbの場合)基本的なWebアプリを作成してきましたが、関数はかなりシンプルなので、ほとんどの人は通常のFORループを使用してデータを取得します。
for i in (select * from STUDENTS) loop
htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;
しかし、カーソルは物事を行う「正しい」方法のようです。カーソルとは何か、さまざまな方法でループする方法については多くの情報を見つけることができますが、通常のFORループでそれらを使用する明確な理由はわかりません。手順の必要性に依存していますか?知っておくべき固有の利点はありますか?
カーソルは明示的または暗黙的にすることができ、どちらのタイプもFORループで使用できます。質問には2つの側面があります。
暗黙的なカーソルFORループではなく明示的なカーソルFORループを使用する理由
明示的なFETCHのないFORループではなく、FETCHを使用したループを使用するのはなぜですか?
これは、ドキュメントからの有用な情報です。
LOOPの暗黙カーソルの例
BEGIN
FOR vItems IN (
SELECT last_name
FROM employees
WHERE manager_id > 120
ORDER BY last_name
)
LOOP
DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
END LOOP;
END;
/
ループの明示的なカーソルの例
DECLARE
CURSOR c1 IS
SELECT last_name
FROM employees
WHERE manager_id > 120
ORDER BY last_name;
BEGIN
FOR vItems IN c1 LOOP
DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
END LOOP;
END;
/
暗黙カーソルは、PL/SQLによって構築および管理されるセッションカーソルです。 PL/SQLは、SELECTまたはDMLステートメントを実行するたびに暗黙カーソルを開きます。暗黙カーソルは制御できませんが、その属性から情報を取得できます。
暗黙のカーソルは、関連するステートメントが実行された後に閉じます。ただし、その属性値は、別のSELECTまたはDMLステートメントが実行されるまで利用可能です。
暗黙的なカーソル属性は、SQL%ISOPEN、SQL%FOUND、SQL%NOTFOUND、SQL%ROWCOUNT、SQL%BULK_ROWCOUNT、SQL%BULK_EXCEPTIONSです。
明示カーソルは、ユーザーが作成および管理するセッションカーソルです。明示的なカーソルを宣言して定義し、名前を付けてクエリに関連付ける必要があります(通常、クエリは複数の行を返します)。次に、次のいずれかの方法でクエリ結果セットを処理できます。
(OPENステートメントで)明示的なカーソルを開き、(FETCHステートメントで)結果セットから行をフェッチし、(CLOSEステートメントで)明示的なカーソルを閉じます。
カーソルFOR LOOPステートメントで明示的なカーソルを使用します(「カーソルFOR LOOPステートメントを使用したクエリ結果セット処理」を参照)。
明示的なカーソルに値を割り当てたり、式で使用したり、仮のサブプログラムパラメータまたはホスト変数として使用したりすることはできません。これらのことは、カーソル変数を使用して行うことができます(「カーソル変数」を参照)。
暗黙カーソルとは異なり、明示カーソルまたはカーソル変数をその名前で参照できます。したがって、明示的なカーソルまたはカーソル変数は、名前付きカーソルと呼ばれます。
カーソルのFOR LOOPステートメントを使用すると、SELECTステートメントを実行し、結果セットの行をすぐにループできます。このステートメントでは、暗黙的または明示的なカーソルを使用できます。
投稿したコードはカーソルを使用しています。暗黙のカーソルループを使用しています。
明示的なカーソルループを使用する(つまり、宣言セクションでCURSOR変数を宣言する)と、コードが簡潔になるか、パフォーマンスが向上する場合があります。
student_cursor
を反復処理すると、一連のロジックを埋め込む30行のSQLステートメントを含めるよりも、コードが読みやすくなります。たとえば、卒業することが許可され、学業成績のあるテーブルへの参加に関与したすべての学生、学位プログラムの要件、学籍情報に関するテーブル、期限切れの図書館の本に関する情報を持つテーブルを印刷する場合、未払い料金、管理オーバーライドなどに関する情報を含むテーブル。コードをリファクタリングして、このクエリがユーザーへのリストの表示に関係するコードの途中で動かなくなることがないようにするのはおそらく意味があります。これには、このすべてのロジックをカプセル化するビューの作成が含まれる場合があります。または、現在のPL/SQLブロックの一部として宣言された明示的なカーソルまたは一部の上位レベルのPL/SQLブロック(つまり、パッケージで宣言されたカーソル)を作成して、再利用できるようにすることもできます。または、カプセル化と再利用のために何か他のことを行う必要があるかもしれません(たとえば、代わりにパイプラインテーブル関数を作成する)。htp.prn
を呼び出すだけの場合は、BULK COLLECT
を実行しても何も購入されない可能性があります。ただし、他の場合では、パフォーマンスが大幅に向上する可能性があります。多くの開発者が、古い習慣から暗黙のカーソルではなく明示的なカーソルを使用していることがわかります。これは、Oracleバージョン7に戻ると、これが常により効率的な方法であったためです。今日では一般的に逆の方法があります。特にオプティマイザを使用すると、必要に応じてループの暗黙カーソルを一括収集に書き換えることができます。
最近、暗黙のFORループからの一連のクエリを明示的なカーソルに書き換える必要がありました。その理由は、クエリがリンクを介して外部データベースからデータをフェッチし、このデータベースがローカルデータベースとは異なるエンコーディングを使用していたためです。暗黙カーソルからローカルに定義されたレコードタイプにデータを転送すると、不思議な断続的なエラーが発生しました(特定の特定の行でのみ)。私たちのDBAはこれを私たちに説明しました、私たちはこれの底に到達することができなかっただろう。これは報告されているOracleのバグのようです。
明示的なカーソルを使用してすべてを書き直すようにアドバイスされ、エラーはなくなりました。
暗黙的ではなく明示的に使用する主な理由ではありませんが、注意する価値があります。
編集:Oracle 12c。