ZetCode

Python sqlite3.Cursor.fetchall 方法

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

本综合指南探讨 Python 的 sqlite3.Cursor.fetchall 方法,这是从 SQLite 数据库检索所有查询结果的主要方式。我们将介绍基本用法、性能考虑因素和实际示例。

基本定义

fetchall 方法检索查询结果集中的所有剩余行。它返回一个元组列表,其中每个元组代表数据库中的一行。

主要特征:它一次性消耗所有结果,如果没有行可用则返回一个空列表,并且应该在执行带有游标的 SELECT 语句后使用。

fetchall 的基本用法

这是 fetchall 的最简单用法,用于检索表中的所有行。 该示例演示了使用上下文管理器的正确资源管理。

basic_fetchall.py
import sqlite3

# Using context managers for both connection and cursor
with sqlite3.connect('example.db') as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM users")
        all_rows = cursor.fetchall()
        
        for row in all_rows:
            print(f"ID: {row[0]}, Name: {row[1]}, Age: {row[2]}")

此示例显示了基本工作流程:连接到数据库,创建游标,执行 SELECT 查询,获取所有结果,并迭代它们。上下文管理器确保正确的资源清理。

fetchall 方法将所有行作为元组列表返回,其中每个元组包含 SELECT 语句中指定的顺序的列值。

获取空结果

当没有行与查询匹配时,fetchall 返回一个空列表,而不是 None 或引发异常。 此示例演示了此行为。

empty_results.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    with conn.cursor() as cursor:
        # Query with no matching rows
        cursor.execute("SELECT * FROM users WHERE age > 100")
        results = cursor.fetchall()
        
        print(f"Number of rows: {len(results)}")  # 0
        print(f"Type of results: {type(results)}")  # <class 'list'>

此示例表明 fetchall 始终返回一个列表,即使未找到任何行。 此行为使其可以安全地迭代结果而无需额外的类型检查。

空列表返回值对于需要以相同方式处理填充和空结果集的条件逻辑非常有用。

与参数化查询结合使用

fetchall 可以与参数化查询无缝协作,这对于防止 SQL 注入至关重要。 此示例演示了这种组合。

parameterized_query.py
import sqlite3

min_age = 25
max_age = 40

with sqlite3.connect('example.db') as conn:
    with conn.cursor() as cursor:
        # Parameterized query with fetchall
        cursor.execute(
            "SELECT * FROM users WHERE age BETWEEN ? AND ?",
            (min_age, max_age)
        )
        
        matching_users = cursor.fetchall()
        for user in matching_users:
            print(user)

此示例演示了如何在查询中安全地使用参数,同时仍然可以从 fetchall 中受益以检索所有匹配的行。 参数作为元组传递给 execute 方法。

参数化查询对于安全性至关重要,并且还可以通过允许 SQLite 重用具有不同值的类似查询的查询计划来提高性能。

处理大型结果集

虽然 fetchall 很方便,但它会一次性将所有结果加载到内存中。 对于大型数据集,请考虑使用 fetchmany 等替代方法。

large_results.py
import sqlite3

with sqlite3.connect('large_db.db') as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM big_table")
        
        # Process in batches to reduce memory usage
        batch_size = 1000
        while True:
            batch = cursor.fetchmany(batch_size)
            if not batch:
                break
                
            for row in batch:
                process_row(row)  # Your processing function

此示例演示了针对大型数据集的更节省内存的方法。 虽然它不使用 fetchall,但了解何时不使用它非常重要。

对于中等大小的结果集(最多数千行),fetchall 是完全可以接受的,并且通常比手动批处理更方便。

与自定义行工厂一起使用

fetchall 可以与自定义行工厂很好地配合使用,这些工厂可以转换行的表示方式。 此示例使用内置的 sqlite3.Row

row_factory.py
import sqlite3

with sqlite3.connect('example.db') as conn:
    conn.row_factory = sqlite3.Row  # Enable named column access
    with conn.cursor() as cursor:
        cursor.execute("SELECT name, age FROM users")
        rows = cursor.fetchall()
        
        for row in rows:
            print(f"{row['name']} is {row['age']} years old")

此示例显示了当使用 sqlite3.Row 工厂时,fetchall 如何返回可以通过索引和列名访问的行。

Row 工厂在便利性和性能之间提供了很好的平衡,使代码更具可读性,同时保持效率。

与 JOIN 操作结合使用

fetchall 可以处理带有 JOIN 的复杂查询,并在一次调用中返回所有相关数据。 此示例演示了一个多表查询。

join_query.py
import sqlite3

with sqlite3.connect('library.db') as conn:
    with conn.cursor() as cursor:
        query = """
        SELECT books.title, authors.name, books.publication_year 
        FROM books
        JOIN authors ON books.author_id = authors.id
        WHERE books.genre = ?
        """
        cursor.execute(query, ('Science Fiction',))
        
        sci_fi_books = cursor.fetchall()
        for book in sci_fi_books:
            title, author, year = book
            print(f"{title} by {author} ({year})")

此示例显示了 fetchall 与 JOIN 查询一起使用,该查询组合了来自多个表的数据。 每个返回的元组都包含来自 JOIN 中所有表的列。

该方法可以像简单单表查询一样很好地处理复杂的结果集,使其适用于各种查询类型。

与聚合函数一起使用

fetchall 可用于使用 COUNT、SUM 或 AVG 等聚合函数的查询。 此示例演示了统计查询。

aggregate_functions.py
import sqlite3

with sqlite3.connect('sales.db') as conn:
    with conn.cursor() as cursor:
        # Multiple aggregate functions in one query
        cursor.execute("""
            SELECT 
                COUNT(*) as total_orders,
                AVG(amount) as avg_amount,
                MAX(amount) as max_sale,
                MIN(amount) as min_sale
            FROM orders
            WHERE order_date BETWEEN ? AND ?
        """, ('2024-01-01', '2024-12-31'))
        
        stats = cursor.fetchall()[0]  # Get first (and only) row
        print(f"Total orders: {stats[0]}")
        print(f"Average amount: ${stats[1]:.2f}")
        print(f"Largest sale: ${stats[2]:.2f}")
        print(f"Smallest sale: ${stats[3]:.2f}")

此示例显示了 fetchall 如何与返回单行计算值的聚合查询一起使用。 我们从结果列表中访问第一行(也是唯一一行)。

即使对于单行结果,fetchall 也会返回包含一个元组的列表,从而在所有查询类型中保持一致的行为。

最佳实践

资料来源

作者

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

列出所有 Python 教程