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(*)で数える

あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら