PL/SQLの勉強10 カーソルのいろいろ

2022-09-28

前回はカーソルの超基本をやっていきました。

カーソルには色々な種類がありますので
それぞれ見ていきたいと思います。

まずはサンプルのデータを用意

前回と同じく…

そんなのいらないよ!
と言う方は、次に行ってくださいw

こんな感じのデータを用意しますよ。

ID名前
1太郎
2花子
3光宙

以下のDDL・DMLを全部コピーして
Oracle Live SQLに貼り付け・実行すれば
自分で試すためのデータは用意できますよ♪

create table COMMON_MST
(
  ID   number
 ,NAME varchar2(4000)
 ,constraint PK_COMMON_MST primary key (ID)
)
;

insert into COMMON_MST values (1, '太郎');
insert into COMMON_MST values (2, '花子');
insert into COMMON_MST values (3, '光宙');

commit;

試しにちゃんとデータが入っているか
確認してみましょう。

select
*
from COMMON_MST
;

大丈夫そうですね!
これでデータの準備はOKです。

カーソルの種類

「カーソル」にはザックリと
2種類あります。

以下の2種類です。

  • 明示カーソル
  • 暗黙カーソル

何が違うかって言うと
カーソルに名前を付けているか?
です。

明示的に名前を付けていれば「明示カーソル」
名前を付けていなければ「暗黙カーソル」

と言うことです!

一つずつ見ていきましょう。。。

明示カーソル

まずは明示カーソルについてです。

明示カーソルの超基本

前回やったカーソルは
明示カーソルの超基本です。

詳しくはこの記事を見て下さいね。

こんな感じに書きましたよね!

declare
  -- カーソルを定義
  cursor cur_common is
    select
      ID
     ,NAME
    from COMMON_MST
  ;
  -- データを保持するための変数を用意
  tbl_common_mst  COMMON_MST%rowtype;
begin
  -- カーソルをオープンする
  open cur_common;
  
  loop
    -- 1行ずつ処理(フェッチ)して、取得したデータを変数に持ち替える
    fetch cur_common into tbl_common_mst;
    -- フェッチしてデータがなかったらloopを修了する
    exit when cur_common%notfound;
    -- 何らかの処理をする(今回は出力だけ)
    dbms_output.put_line(tbl_common_mst.ID || ' : ' || tbl_common_mst.NAME);
  end loop;
  
  -- 最後にカーソルを閉じる
  close cur_common;
  
exception
  when others then
    dbms_output.put_line(SQLERRM);
end;

3行目で「cur_common」という
カーソル名を定義
しています。
名前を定義しているので明示カーソル!

明示カーソルのFORループ

超基本は上記の通りですが、
もっと簡単な書き方も出来ます。

それが「FORループ」と言うもの。
こんな感じに書きますよ。

declare
  -- カーソルを定義
  cursor cur_common is
    select
      ID
     ,NAME
    from COMMON_MST
  ;
begin
  
  -- カーソルをぐるぐる
  for rec_common in cur_common loop
    -- 何らかの処理をする(今回は出力だけ)
    dbms_output.put_line(rec_common.ID || ' : ' || rec_common.NAME);
  end loop;
  
exception
  when others then
    dbms_output.put_line(SQLERRM);
end;

あら簡単♪

超基本の方と比べると
いろいろ省略されてますよね!

  • データを保持するための変数
  • カーソルのOPEN
  • FETCH
  • ループを修了するEXIT
  • カーソルのCLOSE

これらを書かなくても
内部的にやってくれるのが、
「FORループ」と言うやつです。

楽すぎる〜!!

明示カーソルに引数を渡す

明示カーソルに引数を渡す方法
書いておこうと思います。

汎用的なシステムを作るのには必要ですからね!

超基本の方に引数を渡す

例えば
IDは"ある数字"以上の人だけ取りたい!
ってときはどうするか…?

以下のように書きますよ!

declare
  -- カーソルを定義
  cursor cur_common (
    p_id number
  )
  is
    select
      ID
     ,NAME
    from COMMON_MST
    where ID >= p_id
  ;
  -- データを保持するための変数を用意
  tbl_common_mst  COMMON_MST%rowtype;
begin
  -- カーソルをオープンする
  open cur_common(
    p_id => 2
  );
  
  loop
    -- 1行ずつ処理(フェッチ)して、取得したデータを変数に持ち替える
    fetch cur_common into tbl_common_mst;
    -- フェッチしてデータがなかったらloopを修了する
    exit when cur_common%notfound;
    -- 何らかの処理をする(今回は出力だけ)
    dbms_output.put_line(tbl_common_mst.ID || ' : ' || tbl_common_mst.NAME);
  end loop;
  
  -- 最後にカーソルを閉じる
  close cur_common;
  
exception
  when others then
    dbms_output.put_line(SQLERRM);
end;

3行目…
カーソル名を定義しているところに
カッコが増えてますね。
そして、4行目にnumber型のものがあります。

11行目…
number型の「p_id」に
入っている数字以上のものだけを取ってくる!
ってしています。

18行目…
カーソルをOPENする時に
「p_id」には2を入れよ!と
命令しています。

「=>」は矢印なんでしょうね。
“イコール"とか"大なり"とかの意味ではないので
注意ですね!

こんな感じに書くことで
「IDが2より大きいものを取ってきて!」
なプログラムを書いていることになります。

FORループに引数を渡す

さっきと同じことを
明示カーソルのFORループでも
やってみようと思います。

こんな感じに書きますよ!

declare
  -- カーソルを定義
  cursor cur_common (
    p_id number
  )
  is
    select
      ID
     ,NAME
    from COMMON_MST
    where ID >= p_id
  ;
begin
  
  -- カーソルをぐるぐる
  for rec_common in cur_common (
    p_id => 2
  ) loop
    -- 何らかの処理をする(今回は出力だけ)
    dbms_output.put_line(rec_common.ID || ' : ' || rec_common.NAME);
  end loop;
  
exception
  when others then
    dbms_output.put_line(SQLERRM);
end;

変更の仕方はほとんど超基本の方と同じですね。

ただ、こちらはカーソルのOPENが無いので
16行目で引数に値を渡して
います。

暗黙カーソル

暗黙カーソル、
つまりカーソルに名前を付けないでやる方法です。

明示カーソルと違って、こちらは
FORループする方法しか知りません。

と言うか、他に方法あるの?w

こんな感じに書きますよ!

begin
  -- カーソルをぐるぐる
  for rec_common in (
    select
      ID
     ,NAME
    from COMMON_MST
  ) loop
    -- 何らかの処理をする(今回は出力だけ)
    dbms_output.put_line(rec_common.ID || ' : ' || rec_common.NAME);
  end loop;
  
exception
  when others then
    dbms_output.put_line(SQLERRM);
end;

うん、めっちゃシンプル!!

もはや何も定義する必要も無いから
declareも無いw

こんなに種類あって…

明示カーソルとか
暗黙カーソルとか
FORループとか…

こんなに種類あって…
結局どれ使えばいいの?

って感じですよね。

結論だけ言ってしまいます。
あくまで僕の場合ですが。。。

基本は暗黙カーソルしか使っていません!

そして何か特殊なことする時は
明示カーソルの超基本
のやつ。。。

これだけで充分です。

「特殊なこと」って何ぞや?という方に…
Oracle DBを使ったシステムって
時には数千万・数億件のデータを処理します。
するとメモリ不足で処理が落ちたり。。。

そんなことを回避するために、
データを例えば100万件ずつ処理する!
となる必要が出てきます。

これを実現するためには…?
明示カーソルの超基本を
さらに加工すれば出来るようになるんです。

以上ですw

今回は内容が多いですね。
でも覚えることは少ないかと思います。

とりあえず暗黙カーソルを
使えるようになっていればいい!

特殊な状況になった時は
さらにググれば良いのですw

PL/SQL

Posted by kiri