ZetCode

Python sqlite3.Cursor.fetchone 方法

上次修改时间:2025 年 4 月 15 日

本综合指南探讨了 Python 的 sqlite3.Cursor.fetchone 方法,它是从 SQLite 查询结果中检索单个行的主要方法。我们将介绍基本用法、参数和实际示例。

基本定义

fetchone 方法从查询结果集中检索下一行。它返回表示一行的单个序列,如果没有更多数据可用,则返回 None。

主要特点:它对于大型结果集具有内存效率,保持游标位置,并且适用于任何 SELECT 查询。它是 DB-API 2.0 规范的一部分。

fetchone 的基本用法

以下是 fetchone 的最简单用法,用于从数据库表中检索单行。

basic_fetchone.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM users WHERE id = 1")
        row = cur.fetchone()
        print(row)  # (1, 'Alice', 30)

此示例显示了基本工作流程:连接、创建游标、执行查询、获取一行,并自动关闭资源。 with 语句确保适当的清理。

该方法返回一个元组,表示查询顺序中行的列。如果没有行匹配查询,则返回 None。

使用 fetchone 获取多行

可以重复调用 fetchone 以逐行处理结果集。这对于大型结果集具有内存效率。

multiple_fetchone.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM users ORDER BY name")
        while True:
            row = cur.fetchone()
            if row is None:
                break
            print(f"User: {row[1]}, Age: {row[2]}")

此模式在提取每一行时对其进行处理,而无需将所有结果加载到内存中。循环持续到 fetchone 返回 None。

这种方法非常适合内存保存很重要的大型数据集。

将 fetchone 与行工厂结合使用

将行工厂与 fetchone 结合使用可以实现命名列访问,从而提高代码的可读性。

row_factory_fetchone.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    conn.row_factory = sqlite3.Row
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM users WHERE age > ?", (25,))
        row = cur.fetchone()
        if row:
            print(f"{row['name']} is {row['age']} years old")

sqlite3.Row 工厂提供基于索引和名称的列访问。这使得代码更易于维护且不易出错。

当处理具有许多列的表或可能发生模式更改时,命名访问尤其有价值。

处理空结果集

当没有行匹配查询时,fetchone 返回 None。此示例显示了如何正确处理空结果。

empty_results.py
import sqlite3

def get_user_age(user_id):
    with sqlite3.connect('example.db') as conn:
        with conn.cursor() as cur:
            cur.execute("SELECT age FROM users WHERE id = ?", (user_id,))
            row = cur.fetchone()
            return row[0] if row else None

age = get_user_age(999)
print(f"User age: {age if age is not None else 'not found'}")

此示例安全地处理查询未返回任何行的情况。三元运算符在访问其第一列之前检查行是否存在。

使用 fetchone 时,请始终检查 None 以避免 AttributeError 异常。

使用参数化查询的 Fetchone

使用 fetchone 的参数化查询可防止 SQL 注入,并通过查询重用提高性能。

parameterized_fetchone.py
import sqlite3

def authenticate(username, password):
    with sqlite3.connect('users.db') as conn:
        with conn.cursor() as cur:
            query = "SELECT id FROM users WHERE username = ? AND password = ?"
            cur.execute(query, (username, password))
            return cur.fetchone() is not None

authenticated = authenticate('admin', 'secret123')
print("Login successful" if authenticated else "Invalid credentials")

此安全身份验证示例使用参数化查询。?占位符被用户输入值安全地替换。

参数化查询对于安全性至关重要,应始终与用户提供的数据一起使用。

事务中的 Fetchone

fetchone 在事务中工作,允许逐行处理,同时保持数据一致性。

transaction_fetchone.py
import sqlite3

with sqlite3.connect('inventory.db') as conn:
    conn.execute("BEGIN")
    try:
        with conn.cursor() as cur:
            cur.execute("SELECT id, quantity FROM products WHERE quantity < 5")
            while True:
                row = cur.fetchone()
                if row is None:
                    break
                print(f"Low stock: Product {row[0]} has {row[1]} units")
                # Could update each product here
        conn.commit()
    except:
        conn.rollback()
        raise

此示例在事务中处理库存不足的产品。显式的 BEGIN 确保所有获取操作都看到一致的数据库状态。

当获取可能在处理过程中被其他数据库操作更改的数据时,事务非常重要。

使用自定义类型的 Fetchone

SQLite 可以使用转换器或 detect_types 将提取的数据转换为 Python 类型。

custom_types_fetchone.py
import sqlite3
import json
from datetime import datetime

def parse_date(text):
    return datetime.strptime(text, '%Y-%m-%d').date()

with sqlite3.connect('data.db', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS events (id INTEGER, details TEXT, event_date DATE)")
    conn.execute("INSERT INTO events VALUES (1, '{\"type\":\"meeting\"}', '2025-04-20')")
    conn.commit()
    
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM events")
        row = cur.fetchone()
        print(f"Event on {row[2]}: {json.loads(row[1])['type']}")

此示例显示了提取期间的类型转换。 DATE 列被转换为 Python 日期对象,并且 JSON 文本被解析。

类型检测和转换可以简化数据处理,但可能会影响非常大的结果集的性能。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 我从 2007 年开始撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程