カーソル(cursol)とは、データベースの中のデータ(行)を1つずつ見ていくための「目印」や「指標」のようなもの。

イメージとしては、本を読むときに使うしおりのようなものです。ページ(行)を1つずつ開いて読み(処理)進んでいくと考えるとわかりやすいかもしれません。
ポイント カーソル(cursol)
- 1行ずつ処理: カーソルを使うと、データベースの中の情報(行)を1つずつ取り出して処理ができる。
- 大量のデータも安心: たくさんのデータがある場合でも、一度にすべてを読み込む必要がないので、パソコンが重くなりにくい。
- 自由な操作: カーソルが指し示す各行に対して、様々な処理(読み取り、更新、削除など)を行うことができる。
- 順番に処理: カーソルはデータベースの中を順番に移動しながら、必要な処理を行う。

このページはカーソルって何?という方のために、基本的な意味や具体的な実装方法までを簡潔にわかりやすく解説します。
プログラマーやシステムエンジニアを目指す方であれば、知らないと恥ずかしい超・基本知識の1つ。是非最後までご覧ください。
カーソル(cursol)とは?
冒頭でも解説した通り、カーソル(cursol)とはデータベースの中のデータ(行)を1つずつ見ていくための「目印」や「指標」のようなものです。

言葉だけではイメージしづらいかもしれませんので、実際の例を見ながら学習を進めていきましょう!
カーソルを利用するシナリオ
students
テーブルがあり、id
とname
というフィールドが存在する。- カーソルを使って、特定の条件に一致する学生(
student
)の名前(name
)を"John Doe"に変更します。
ステップ1 カーソルの定義
最初に、条件に一致するid
を取り出す(SELECTする)カーソルを宣言します。
DECLARE my_cursor CURSOR FOR SELECT id FROM students WHERE name='John';

上記SQLの詳細は↓の通り。

ざっくりいえば、John という行に合致する行に本のしおり(=カーソル)を挟むようなイメージです。
DECLARE
: 変数やカーソルを宣言するSQLキーワード。my_cursor
: カーソルの名前。CURSOR FOR
: カーソルで処理するSQLクエリを指定。SELECT id FROM students WHERE name='John'
: 実行するSQLクエリ。

本来MySQLでは、カーソルはストアドプロシージャや関数内でしか宣言できませんが、ここでは理解促進のためあえてコードを改変しています。
ステップ2 カーソルを開く
OPEN my_cursor;
ステップ3 データの取得
カーソルから次のid
を取り出し、一時的な変数(たとえば@student_id
)に格納します。
FETCH my_cursor INTO @student_id;
FETCH
: カーソルからデータを一行取り出す。INTO @student_id
: 取り出したデータを@student_id
変数に格納。
ステップ4 特定の行を更新
ここでカーソルが指している行の名前を"John Doe"に更新します。
UPDATE students SET name='John Doe' WHERE CURRENT OF my_cursor;
UPDATE students SET name='John Doe'
:students
テーブルのname
列を"John Doe"に更新します。WHERE CURRENT OF my_cursor
: カーソルが現在指している行だけを更新。
ステップ5 カーソルを閉じる
CLOSE my_cursor;
1. データの集計
行ごとに特定の計算を行い、その結果を集計する際にカーソルが役立ちます。
-- カーソルを宣言 DECLARE sales_cursor CURSOR FOR SELECT amount FROM sales; -- 変数を宣言 DECLARE @total_sales INT; SET @total_sales = 0; -- カーソルを開く OPEN sales_cursor; -- 各行を処理 -- FETCH NEXT: カーソルが現在指している位置から次の行に移動。 FETCH NEXT FROM sales_cursor INTO @amount; WHILE @@FETCH_STATUS = 0 BEGIN SET @total_sales = @total_sales + @amount; FETCH NEXT FROM sales_cursor INTO @amount; END; -- カーソルを閉じる CLOSE sales_cursor;
2. 条件に基づくデータの更新
特定の条件に合致する行だけを対象としてデータを更新する場合にカーソルが有用です。
-- カーソルを宣言 DECLARE student_cursor CURSOR FOR SELECT id FROM students WHERE grade < 60; -- 変数を宣言 DECLARE @student_id INT; -- カーソルを開く OPEN student_cursor; -- 各行を処理 FETCH NEXT FROM student_cursor INTO @student_id; WHILE @@FETCH_STATUS = 0 BEGIN UPDATE students SET status = 'Failed' WHERE id = @student_id; FETCH NEXT FROM student_cursor INTO @student_id; END; -- カーソルを閉じる CLOSE student_cursor;
3. データのエクスポート
行ごとにデータをファイルや外部システムにエクスポートする際にもカーソルが役立つ場合があります。
-- カーソルを宣言 DECLARE export_cursor CURSOR FOR SELECT name, email FROM users; -- 変数を宣言 DECLARE @name VARCHAR(50), @email VARCHAR(50); -- カーソルを開く OPEN export_cursor; -- 各行を処理 FETCH NEXT FROM export_cursor INTO @name, @email; WHILE @@FETCH_STATUS = 0 BEGIN -- ここで、@nameと@emailを外部ファイルやシステムにエクスポートするロジックを実装 FETCH NEXT FROM export_cursor INTO @name, @email; END; -- カーソルを閉じる CLOSE export_cursor;
実践:MySQLにおけるカーソルの利用
先ほども述べた通りカーソル(cursol)は、一般的にカーソルはストアドプロシージャや関数内でしか使えません。

実際にカーソルを利用する際のサンプルコードをお見せします。
DELIMITER // CREATE PROCEDURE ListStudentNames() BEGIN DECLARE done INT DEFAULT 0; DECLARE student_id INT; DECLARE student_name VARCHAR(255); -- ↓の行でstudentsテーブルからIDと名前を選択するカーソルを宣言。 DECLARE cur CURSOR FOR SELECT id, name FROM students; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; -- カーソルを開く OPEN cur; read_loop: LOOP -- カーソルからレコードを取得し、その値を変数student_idとstudent_nameに格納します。 FETCH cur INTO student_id, student_name; -- カーソルが最後の行に達したかどうかを確認→最後の行ならループを終了 IF done THEN LEAVE read_loop; END IF; SELECT CONCAT('Student ID: ', student_id, ', Name: ', student_name); END LOOP; CLOSE cur; END; // DELIMITER ;
このMySQLのストアドプロシージャでは、カーソルを使ってstudents
テーブルから学生の情報を一行ずつ取得し、その名前を出力しています。

このように、カーソルは行を一つずつ処理する複雑なロジックを実装する場合に非常に便利です。
以下は、PythonとSQLiteを使用してカーソルを使う簡単な例です。
import sqlite3 # データベースに接続 conn = sqlite3.connect('example.db') cursor = conn.cursor() # SQLクエリを実行 cursor.execute('SELECT * FROM table_name') # 結果を一行ずつ取得して処理 for row in cursor: print(row) # 出力: テーブルの各行の内容 # カーソルと接続を閉じる cursor.close() conn.close()
このようにカーソルの考え方はデータベースを操作する他のプログラムでも応用されます。
参考 Pythonの基本
カーソルを利用するメリット
カーソルを利用する主なメリットは、データの行に対して個別に処理を行える点です。
SQLは基本的にセット操作が得意ですが、一度に多数の行を処理する場合、リソースの消費が大きくなったり、一部の行に対して特別な操作を行いたい場合には不便です。カーソルはこのようなシナリオで有用であり、行単位での処理を効率よく、かつ柔軟に行うことができます。

また、処理中に他の操作を挟むことが容易であり、複雑なビジネスロジックを組み込む際にも役立ちます。
まとめ:カーソル(cursol)とは?
SQLやデータベースの仕組みを1から学習したい方(学び直したい方)向けに、現役エンジニア達のスキルを結集して 完全無料 のSQL教材を作成しました。

SQLは決して難しい技術ではないので、エンジニアであれば「当たり前のように」扱えて当然かも・・・?
とはいえ、案外SQLをちゃんと使ったことがない人も多いはずです。この機会に是非一度ご覧になってみてください。