【データベース】CURSOR(カーソル)とは、仕組みや使い方についてわかりやすく解説!

今回はデータベースのストアドプロシージャなどでよく見かけるCURSOR(カーソル)について解説いたします。

データベースで急に出てくると普通のクエリとは違ってシステマチックな動きをするのでよくわからなかったり、理解するのに苦労したりすると思います。

そこで今回はカーソルの動きをイメージで捉えられるように図を用いて一つ一つ解説していきたいと思います。
初心者の方でもわかりやすいような内容になっていると思いますので、本記事でカーソルについて完璧に理解できたなら幸いです。

スポンサーリンク
目次

CURSOR(カーソル)とは

まずはカーソルについてですが、CURSOR(カーソル)とはその名の通り、データベースの処理の位置を示すポインターのことで、取得した情報に対して一行ずつ処理を行うための仕組みです。

ただ、その名の通りといってもこれがしっくりこない方が多いと思いますので、具体的に説明します。

①まずカーソルは変数として宣言するのですが、その中には何らかのクエリで取得した結果セットが格納されています。

②これを “FETCH” という作業で上から順番にデータを1行ずつ抜き出していき、今どこの行を見ているのかをポインターで保持しているというのがカーソルの主な仕組みになります。

このように、クエリを発行させ結果セットを1行ずつ上から順にデータを見ていくのがCURSORの主な役割となります。

チェックポイント

1. CURSORに結果セットを格納する
2. FETCHで上から順に処理!

CURSORの具体的な使用例

それでは次にCURSORの具体的な使用例をご紹介いたします。
CURSORは基本的に以下の手順に沿って使用しますので、それぞれStepごとに解説いたします。

1. CURSORを宣言する
2. CURSORをオープンする
3. CURSORから1行データを抜き出す
4. 条件を設定し、条件の内容にそって処理をする
5. 1行処理が終わったら次のデータを1行取得し、4の処理を続ける
6. 処理が終わったらCURSORをクローズする。

それでは条件に合致するデータを別のテーブルに格納したいという例をもとにStep毎の処理を見ていきましょう。

なお書き方はSQLServerだったり、Postgreだったり、OracleだったりDBの種類で変わりますが、今回はSQLSeverの書き方に倣って解説いたします。

それぞれ処理毎に解説いたしますが、今回のプログラムの全体像は以下のようになります。

DECLARE CSR CURSOR FOR –①

SELECT
COL1
,COL2
,COL3
,COL4
,COL5
FROM
ORI_TABLE –コピー元のテーブル
WHERE
COL1 = “データ1”
AND COL3 = “値3”
ORDER BY
COL1
, COL2

OPEN CSR –②

BEGIN –③
/*選択したデータの格納用の変数*/
DECLARE @vCOL1 varchar(20)
DECLARE @vCOL2 varchar(20)
DECLARE @vCOL3 varchar(20)
DECLARE @vCOL4 varchar(20)
DECLARE @vCOL5 varchar(20)

/*変数の初期化*/
@vCOL1 = “”
@vCOL2 = “”
@vCOL3 = “”
@vCOL4 = “”
@vCOL5 = “”

/*データの取得と格納*/
FETCH NEXT FROM CSR
INTO @vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5

/* FETCHする行がある間処理を続ける*/ –④
WHILE @@FETCH_STATUS = 0
BEGIN –処理の開始

INSERT INTO CLONE_TABLE –コピー先のテーブル
(
COL1
,COL2
,COL3
,COL4
,COL5
) VALUES (
@vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5
)

/*データの取得と格納*/
FETCH NEXT FROM CSR –⑤
INTO @vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5
END

END –⑥
CLOSE CSR
DEALLOCATE CSR

1. CURSORを宣言する

まずはCURSORを宣言します。
CURSORには何らかのデータを入れないと始まらないので、データを取得するクエリとセットで以下のように書きます。

DECLARE CSR CURSOR FOR

SELECT
COL1
,COL2
,COL3
,COL4
,COL5
FROM
ORI_TABLE –コピー元のテーブル
WHERE
COL1 = “データ1”
AND COL3 = “値3”
ORDER BY
COL1
, COL2

これで上記で示したと同じ状況になります。

2. CURSORをオープンする

次にCURSORを使える状態にするため、CURSORのオープンを行います。
所謂使用開始宣言みたいなものです。
ただ単に OPEN <カーソル名> と記載するだけです。

OPEN CSR

3. CURSORから1行データを抜き出す

それでは実際の処理に入っていきます。
まずはFETCHで最初の1行を以下のように取得します。

BEGIN
/*選択したデータの格納用の変数*/
DECLARE @vCOL1 varchar(20)
DECLARE @vCOL2 varchar(20)
DECLARE @vCOL3 varchar(20)
DECLARE @vCOL4 varchar(20)
DECLARE @vCOL5 varchar(20)

/*変数の初期化*/
@vCOL1 = “”
@vCOL2 = “”
@vCOL3 = “”
@vCOL4 = “”
@vCOL5 = “”

/*データの取得と格納*/
FETCH NEXT FROM CSR
INTO @vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5

データの取得の前にデータを入れるための変数を用意し、用意した変数にINTOで取得したデータがカラムごとに格納される形です。
上記はSQLServerでの書き方で、他のDBだと一行丸っと持ってこれたりもします。
また、カラムの値をどの変数に入れるかは明示的に記載する必要性がなく、頭のカラムから順番に格納されます。(SQLServerであれば)

4. 条件を設定し、条件の内容にそって処理をする

次は1行ごとに処理をしたい内容を書きます。
データベースのプログラミングなので、クエリを書くことが基本になるでしょう。

ここでは別のテーブルにデータを入れるクエリを書くのでINSERT文を記載します。

/* FETCHする行がある間処理を続ける*/
WHILE @@FETCH_STATUS = 0
BEGIN –処理の開始

INSERT INTO CLONE_TABLE –コピー先のテーブル
(
COL1
,COL2
,COL3
,COL4
,COL5
) VALUES (
@vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5
)

/*5. の処理*/

“WHILE @@FETCH_STATUS = 0” は「次の行がある限り処理をループしますよ」という意味です。

処理は”BEGIN” ~ “END” までが対象です。

5. 1行処理が終わったら次のデータを1行取得し、4の処理を続ける

上記のINSERT文を書けばあとはループして全行に対してINSERTしてくれそうですが、この場合はそうではありません。
ループ処理はWHILEの中で行われますが、FETCHした行を変数に入れている処理はWHILE文の外にあるので、WHILEの中で、処理が終わったら改めて記載する必要があります。

/* 4の処理の続き*/

/*データの取得と格納*/
FETCH NEXT FROM CSR
INTO @vCOL1
,@vCOL2
,@vCOL3
,@vCOL4
,@vCOL5
END

6. 処理が終わったらCURSORをクローズする。

最後にCURSORを閉じます。要はカーソルの処理はここで終わりだよという意味です。

これをやらないと例えば毎日定刻にこの処理を実行する際にカーソルがクローズされずオープンのままの場合、
最初に書いた「OPEN CSR」で「カーソルはすでに開かれています。」というような旨のエラー分が発生してしまいます。

そのため、処理がいったん終わったカーソル必ずCLOSEする必要があります。

END
CLOSE CSR
DEALLOCATE CSR

カーソルをオープンした後 “BEGIN” にて処理を開始したと思いますが、その処理をまずは “END” で閉じてからクローズをします。
SQLServerの場合はカーソルをクローズした後、メモリから解放するために “DEALLOCATE” を使います。

なお、クローズする前に何らかの処理で途中終了してしまった場合、カーソルは開きっぱなしになってしまいますので、「カーソルをオープンする前にすでにカーソルが存在したらいったん閉じる」というような処理を書いておくと安心です。



–カーソルが閉じられていなかった時用に
IF (SELECT CURSOR_STATUS(‘global’,’CUR_CHK’)) >= -1
BEGIN
IF (SELECT CURSOR_STATUS(‘global’,’CUR_CHK’)) > -1
BEGIN
CLOSE CUR_CHK
END
DEALLOCATE CUR_CHK
END

いかがでしたでしょうか。
CURSORの使い方については簡単ですが、以上です。

私も最初カーソルを処理を見たときは理解するのに大分苦労した思い出があるので、
この記事が皆様の理解の助けになれば幸いです。

わかりにくいところ、間違っているところ等ございましたら、ご連絡いただけますと幸いです。

今回はここまでです。
お疲れ様でした。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

本業ではPHPを使ったWEBアプリやJavaを使用した基幹アプリを作成しております。Pythonは個人的に勉強しており、E資格を取ったりしたおかげで、業務でAIの研究とかも任されるようになりました。学習のアウトプットのために本サイトを運営しておりますが、これからPythonを学ぶという人のお役に立てればいいなと思います。わからないことや調査して記事にしてほしいことがございましたらご連絡いただけると幸いです。

コメント

コメントする

目次
閉じる