Python Cursor.fetchone()とは?1行ずつ取得する方法
PythonのCursor.fetchone()は、検索結果から1行だけ取り出すメソッドです。
「1件だけ欲しい」場面と、巨大な結果をメモリに載せずに処理したい場面で使います。
Cursor.fetchone()の基本的な使い方
import sqlite3
conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
cur.executemany("INSERT INTO users (name, age) VALUES (?, ?)",
[("佐藤", 28), ("鈴木", 34), ("高橋", 22)])
cur.execute("SELECT id, name, age FROM users ORDER BY id")
print(cur.fetchone())
print(cur.fetchone())
conn.close()
実行結果:
(1, '佐藤', 28)
(2, '鈴木', 34)
呼ぶたびに次の行へ進みます。カーソルが読み取り位置を覚えているためです。
戻り値はタプル
row = cur.execute("SELECT id, name, age FROM users").fetchone()
print(type(row).__name__)
print(row[1])
実行結果:
tuple
佐藤
列はSELECTに書いた順番で並びます。row[1]のような添字アクセスは、列の順番が変わると壊れます。
列が多いならsqlite3.Rowを使うと列名でアクセスできます。
conn.row_factory = sqlite3.Row
cur = conn.cursor()
row = cur.execute("SELECT id, name, age FROM users").fetchone()
print(row["name"], row["age"])
実行結果:
佐藤 28
該当がなければNoneが返る
ここが最大の注意点です。
cur.execute("SELECT * FROM users WHERE id = 9999")
print(cur.fetchone())
実行結果:
None
例外ではなくNoneです。そのまま使うとエラーになります。
row = cur.execute("SELECT name FROM users WHERE id = 9999").fetchone()
print(row[0])
実行結果:
TypeError: 'NoneType' object is not subscriptable
必ず確認してから使ってください。
row = cur.execute("SELECT name FROM users WHERE id = ?", (9999,)).fetchone()
if row is None:
print("見つかりませんでした")
else:
print("名前:", row[0])
実行結果:
見つかりませんでした
if row:ではなくif row is None:と書くのが安全です。(0,)や('',)のような行は偽と判定されないので実害は出にくいのですが、意図を明確にするうえでもis Noneが適切です。
1件だけ欲しいならLIMITを付ける
row = cur.execute("SELECT * FROM users ORDER BY age DESC LIMIT 1").fetchone()
print(row)
実行結果:
(2, '鈴木', 34)
fetchone()は1行だけ取り出しますが、SQL自体は全件を対象に動きます。100万件から1件取るなら、LIMIT 1を付けたほうがデータベース側の負担が減ります。
大量データを1行ずつ処理する
fetchone()のもう1つの用途です。
cur.execute("SELECT id, name FROM users ORDER BY id")
while True:
row = cur.fetchone()
if row is None:
break
print("処理:", row)
実行結果:
処理: (1, '佐藤')
処理: (2, '鈴木')
処理: (3, '高橋')
fetchall()だと全件がメモリに載ります。100万行なら数百MBになることもあります。fetchone()なら1行分だけです。
ただし、この用途ならforで直接回すほうが簡潔です。
for row in cur.execute("SELECT id, name FROM users ORDER BY id"):
print("処理:", row)
カーソルはイテレータとして使えます。内部の動きはfetchone()のループと同じで、メモリ効率も変わりません。
| 場面 | おすすめ |
|---|---|
| 1件だけ取る | fetchone() |
| 全件を順に処理する | for row in cur: |
| 件数が少なくリストが欲しい | fetchall() |
| 一定件数ずつ処理する | fetchmany(n) |
| 途中で止める条件がある | fetchone()+while |
件数を数えるときは使わない
row = cur.execute("SELECT COUNT(*) FROM users").fetchone()
print("件数:", row[0])
実行結果:
件数: 3
これは正しい使い方です。一方、全件取ってから数えるのは無駄です。
n = len(cur.execute("SELECT * FROM users").fetchall()) # 非効率
データベース側で数えられることは、データベースにやらせてください。
fetchoneとfetchallの違い
| 項目 | fetchone() |
fetchall() |
|---|---|---|
| 戻り値 | 1行(タプル) | 全行(リスト) |
| 該当なし | None |
[] |
| メモリ | 1行分 | 全件分 |
| 位置 | 1つ進む | 最後まで進む |
「該当なし」の表現が違う点に注意してください。fetchall()は空リストなのでif rows:で判定できますが、fetchone()はNoneです。
Cursor.fetchone()のまとめ
fetchone()は1行取り出して次へ進む- 戻り値はタプル。列名で読むなら
sqlite3.Row - 該当がなければ
None——確認してから使う - 1件だけ欲しいときは
LIMIT 1を付ける - 全件処理なら
for row in cur:が簡潔 - 件数は
SELECT COUNT(*)で数える



