FETCHを使ってループ処理を行う(SELECTで取得したデータをカーソルで参照)[SQL Server]

プログラムを使用すれば、SQLのSELECTステートメントで取得したデータをループして1件ずつ処理することができますが、仕様によっては、データベース側でループ処理を行いたい場合もあります。

例えば、ストアドプロシージャ内でSELECTを使用して取得したデータをループして、そのデータをもとに特定のテーブルにデータを更新したい場合などです。

このような場合にSQLServerでは、FETCHステートメントを使用することができます。

今回は、サーバーカーソルから特定の行を取得してループ処理を行うFETCHを紹介します。

本記事で使用するサンプルテーブル

本記事ではFETCHを使用したSQLのサンプルとして、以下のテーブルを使用します。

テーブルは、会員の個人情報を管理する「会員」テーブルと、会員の連絡先情報を管理する「連絡先」テーブルの2つを作成します。

テーブルの列定義

テーブルの列定義は次のようになります。

会員テーブル

列名 データ型 NULL許容 主キー
会員番号 int No
nvarchar(50) No
nvarchar(50) No
性別 varchar(10) Yes
生年月日 date Yes

連絡先テーブル

列名 データ型 NULL許容 主キー
会員番号 int No
連絡先番号 tinyint No
電話番号 varchar(20) Yes
メールアドレス varchar(254) Yes
備考 nvarchar(200) Yes

テーブルを作成するCREATE文(SQL)

テーブルを作成するSQLのCREATE文は次のようになります。

会員テーブル

連絡先テーブル

テーブルにデータを挿入するINSERT文(SQL)

テーブルにデータを挿入するSQLのINSERT文は次のようになります。

会員テーブル

FETCHとは

FETCHは、データベースから取得したデータを1件ずつ参照する機能です。
FETCHでは、カーソル(CURSOR)を使用します。

カーソルとは、取得結果からデータを1件ずつ抜き取るための仕組みです。
カーソルは、取得したデータ(表)の位置(行)情報を持っています。

FETCHでは、カーソルを利用してデータを1行ずつループすることで、値を参照することができます。

FETCHステートメントの使用例

ここでは、FETCHステートメントを使用した簡単な例をいくつか紹介します。

単純なフェッチ

次の例では、「会員」テーブルのすべての行に対して単純なカーソルを宣言し、FETCH NEXTを使用して行を順番に移動します。
FETCHステートメントは、DECLARE CURSORステートメントで宣言された列の値を、単一行の結果セットとして返します。

FETCHステートメントを使用する際は、まずカーソルを宣言(定義)します。

宣言したカーソルはOPENステートメントで開きます。

カーソルが開けたら、「FETCH NEXT」で行を移動します。
初回の「FETCH NEXT」で、取得したデータ(結果表)の先頭行に移動することができます。

「WHILE @@FETCH_STATUS = 0」でフェッチの状態を確認します。
WHILEループでは、フェッチが可能な間処理を行います。
ループ内で「FETCH NEXT」を実行することで次の行に移動することができます。

カーソルが最終行まで移動したらWHILEループを抜けますので、カーソルを閉じて割り当てを解除します。

上記のSQLをSQL Server Management Studio(SSMS)実行すると、次のような結果になります。

SQL Server 単純なFETCHステートメントの実行例

データの中身(列の値)を参照して変数に格納する

次の例では、「会員」テーブルのすべての行に対してカーソルを宣言し、FETCHステートメントで変数に値を格納します。

FETCHで変数に値を格納する際は、INTOを使用します。

INTOの後にSELECTで取得する列の順番に、変数を記述します。

フェッチで取得する列の数と値を格納する変数の数が一致していない場合には、以下のエラーメッセージが表示されます。

カーソル フェッチ: INTO リストで宣言する変数の数は、選択される列の数と一致させてください。

参照したデータをもとに別のテーブルを更新する

次の例では、FETCHステートメントで値を格納した変数を利用して、別のテーブルを更新(INSERT)します。

FETCHで値を格納した変数は、INSERT、UPDATE、DELETEなどのSQLの実行に使用できます。

これを利用する事で、通常のSQLでは実現できない処理を行うストアドプロシージャなどを作成することできます。

SCROLLカーソルを宣言して様々なFETCHを行う

ここまでの例では、DECLARE カーソル CURSOR FORでカーソルを宣言してきました。
この宣言の仕方の場合には、カーソルは順方向専用(先頭から末尾に進むのみ)のカーソルになります。

取得したデータを上から順番に読み込んでいくフェッチ処理の場合は、順方向専用のカーソルを宣言して、FETCH NEXTでカーソルをすすめていきますが、SQLServerには、カーソルを先頭や末尾に移動したり、指定した位置の行にカーソルを移動するオプションも用意されています。

FETCHオプションにはNEXTの他に
PRIOR
FIRST
LAST
ABSOLUTE
RELATIVE
があります。

「PRIOR」は、現在のカーソルがある行の1つ前の行に移動します。
「FIRST」は、カーソル内の先頭行に移動します。
「LAST」は、カーソル内の最終行移動します。
「ABSOLUTE」は、指定した行数の番号(n行目)の行に移動します。
「RELATIVE」は、現在のカーソルがある行を起点として上または下に指定した行数の分だけ移動します。

以下にFETCHステートメントで使用できるオプションの使用例を示します。

「NEXT」以外のオプションを利用する場合は、カーソルの宣言時にSCROLLを指定してDECLARE カーソル SCROLL CURSOR FORとします。

上記のSQLをSQL Server Management Studio(SSMS)実行すると、次のような結果になります。

SQL Server FETCHステートメントのオプション実行例

「ABSOLUTE」と「RELATIVE」では、数値でカーソル位置を指定します。
「RELATIVE」で0より小さい数値を指定すると上方向(逆方向)にカーソルが移動します。

カーソルの種類(オプション)

カーソルには、SCROLLオプション以外にも
FORWARD_ONLY
FAST_FORWARD
DYNAMIC
などがあります。

カーソルの種類(オプション)をはじめ、SQL ServerのFETCHの詳細については、以下のドキュメントが参考になります。

Microsoft SQL Server FETCH (Transact-SQL)