Python sqlite3.Row 怎样按列名读取查询结果
Python 的 sqlite3 查询默认返回元组,所以 row[0] 能取到第一列,但 row["name"] 会失败。要按列名读取,只需在创建游标之前把连接的 row_factory 设置为 sqlite3.Row;之后用 row["列名"]、row[索引] 或 row.keys() 访问即可。
官方文档:https://docs.python.org/3/library/sqlite3.html
核心写法是con = sqlite3.connect(":memory:")后执行con.row_factory = sqlite3.Row。这个设置只会影响之后从该连接创建的游标,已有游标不会自动切换。
默认元组为什么不适合按列名读取
查询结果的形状由连接或游标上的 row_factory 决定。默认值是 None,因此每一行是元组,列顺序完全由 SELECT 子句决定。元组适合位置固定、字段很少的场景,但当 SQL 增加列或调整投影顺序时,连续的数字下标容易变得不直观。
sqlite3.Row 是内置的行工厂,支持迭代、按索引访问和按列名映射访问。它不是普通字典,不能把所有字典方法都当作可用接口;需要列名清单时,使用它提供的 keys()。

先在连接上设置 sqlite3.Row
推荐把设置放在连接初始化阶段。这样从该连接后续创建的游标都会采用相同的行表示,业务函数不需要反复转换结果。
import sqlite3
# 连接级设置会传给之后创建的游标,适合统一约定查询结果形状。
con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row
# 用别名让返回对象拥有稳定、可读的列名。
con.execute("CREATE TABLE user_profile (user_id INTEGER, display_name TEXT)")
con.execute(
"INSERT INTO user_profile (user_id, display_name) VALUES (?, ?)",
(7, "林默"),
)
# 查询返回 Row,而不是普通 tuple。
row = con.execute(
"SELECT user_id, display_name FROM user_profile WHERE user_id = ?",
(7,),
).fetchone()
if row is not None:
# 列名访问表达业务字段;索引访问仍然保留,便于兼容旧代码。
print(row["display_name"])
print(row[0])
# 连接不再使用时显式关闭,避免把资源生命周期交给垃圾回收。
con.close()
这里使用参数占位符传入用户编号,避免把外部输入拼进 SQL。fetchone() 找不到记录时返回 None,所以按列名读取前仍要先判断结果是否存在。
按列名读取时,列名来自 SELECT 结果
Row 的访问键不是 Python 变量名,而是查询结果中的列名。推荐在投影中明确写出字段,并在表达式或联表场景中使用 AS 起别名:
# 别名决定 Row 中的键,避免把表达式原文当作业务字段名。
row = con.execute(
"SELECT user_id AS id, display_name AS name "
"FROM user_profile WHERE user_id = ?",
(7,),
).fetchone()
if row is not None:
# keys() 返回当前查询结果的列名列表,可用于展示或调试。
print(row.keys())
print(row["id"], row["name"])
官方文档说明,列名访问不区分大小写,因此 row["name"] 与 row["NAME"] 可以指向同一列。但工程上仍建议统一 SQL 别名大小写,避免不同数据库或人工维护时产生阅读差异。
老游标为什么仍然返回元组
一个容易被忽略的迁移边界是设置时机。连接的 row_factory 是新游标的初始配置;如果游标已经创建,再修改连接属性,已有游标不会自动更新。
import sqlite3
con = sqlite3.connect(":memory:")
old_cursor = con.cursor()
# 这个设置不会回溯修改已经创建的 old_cursor。
con.row_factory = sqlite3.Row
new_cursor = con.cursor()
# 旧游标与新游标的行类型可能不同;迁移时应统一创建顺序。
old_cursor.execute("SELECT 1 AS value")
new_cursor.execute("SELECT 1 AS value")
old_row = old_cursor.fetchone()
new_row = new_cursor.fetchone()
print(type(old_row).__name__, type(new_row).__name__)
old_cursor.close()
new_cursor.close()
con.close()
如果项目封装了连接池或游标工厂,最稳妥的做法是在连接交给业务代码前就设置 row_factory,并避免在中途对同一连接混用两种结果形状。
重复列名和空结果要单独处理
Row 能按列名读取,但它不能替调用方解决重复列名。联表查询如果同时选择两个同名字段,访问某个重复键时应先给列起明确别名;否则读者看到的键与实际业务含义并不匹配。
# 联表时主动区分两个 id,避免 Row 的列名含义不清。
row = con.execute(
"SELECT u.user_id AS user_id, o.order_id AS order_id "
"FROM user_profile AS u JOIN orders AS o ON o.user_id = u.user_id "
"WHERE u.user_id = ?",
(7,),
).fetchone()
if row is None:
# 没有匹配行时不能直接写 row["order_id"]。
print("没有订单")
else:
print(row["user_id"], row["order_id"])
如果业务需要字典序列化,可以在边界处显式转换,例如用 {key: row[key] for key in row.keys()} 生成普通字典。不要为了方便把所有查询都改成自定义字典工厂:字典更适合需要 JSON 化的边界,Row 更适合保留轻量的按名、按索引读取能力。

迁移时可以按这张表快速判断
| 场景 | 建议 | 原因 |
|---|---|---|
| 字段位置长期固定 | 保留元组 | 下标简单且无额外命名约定 |
| 查询字段会调整 | 使用 sqlite3.Row | 按列名表达业务含义 |
| 联表有同名字段 | 用 AS 起别名 | 避免键名含义不清 |
| fetchone() 可能为空 | 先判断 None | 避免对空结果按键读取 |
| 需要输出 JSON | 边界处转 dict | 不要让内部结果形状扩散到所有层 |
最小核对顺序是:连接设置是否早于游标创建;SQL 是否给表达式和联表字段命名;读取前是否处理 None;循环读取时是否只使用当前查询返回的键。这样就能把“按列名读取”从一处技巧变成稳定的数据访问约定。
sqlite3.Row 能不能像字典一样调用 get?
不要把它当作完整字典使用。按列名读取用下标语法,列名清单用 keys();如果确实需要 get() 等字典行为,在边界处显式转换为字典。
可以只给一个游标设置 row_factory 吗?
可以,游标的 row_factory 也能单独设置。但连接级设置更容易保持多个游标的一致性;只影响单个查询时才考虑游标级覆盖。
列名访问大小写不敏感,还要统一别名吗?
要。大小写不敏感解决的是访问便利,不解决联表重复字段、表达式名称不稳定和团队阅读问题。统一别名仍然是更清晰的接口约定。
Python sqlite3.Row 的关键不是把查询结果“变成字典”,而是为同一行保留轻量的列名映射。把设置放在连接初始化阶段,用明确的 SQL 别名,并在读取前处理空结果,基本就能覆盖按列名读取时最常见的迁移问题。
Python pathlib.Path.walk 怎样用 on_error 处理遍历异常
- 上一篇
- Python pathlib.Path.walk 怎样用 on_error 处理遍历异常
- 下一篇
- Python sqlite3.blobopen 怎样读写 SQLite 的大二进制字段
-
- 文章 · python教程 | 27分钟前 |
- Python zipfile.ZipFile.open 怎样按二进制流读取压缩成员
- 340浏览 收藏
-
- 文章 · python教程 | 46分钟前 | python · Python 进程间通信 multiprocessing shared_memory ShareableList
- Python ShareableList 固定长度共享列表的类型与容量边界
- 163浏览 收藏
-
- 文章 · python教程 | 1小时前 | 工程实践 · Python教程 · Python 对象生命周期 weakref weakref.finalize 清理回调
- Python weakref.finalize 怎样为对象注册清理回调
- 200浏览 收藏
-
- 文章 · python教程 | 1小时前 | python · Python TypeGuard 类型收窄 typing.TypeIs
- Python typing.TypeIs 怎样表达更精确的类型收窄
- 218浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python dataclasses.field 怎样声明不可共享的默认值
- 250浏览 收藏
-
- 文章 · python教程 | 2小时前 | Python asyncio CancelledError 异步超时 asyncio.timeout TimeoutError
- Python asyncio.timeout 怎样把超时变成可捕获异常
- 419浏览 收藏
-
- 文章 · python教程 | 2小时前 | 消息队列 · python · 异步编程 · Python asyncio Queue.shutdown QueueShutDown
- Python asyncio.Queue.shutdown 怎样让生产者和消费者安全收尾
- 312浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 843次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 843次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 925次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 900次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 729次使用
-
- Go database/sql QueryRowContext 找不到记录时怎么判断
- 2026-09-15 457浏览
-
- Go Rows.Err 在迭代结束后的错误检查
- 2026-09-29 266浏览
-
- Go SQLX MapScan 读取动态列结果的字段映射方法
- 2026-10-29 455浏览
-
- Go SQLX Select 为什么不适合无限制加载大结果集
- 2026-10-29 243浏览
-
- Navicat for SQLite导入csv中文数据的方法
- 2022-12-29 378浏览

