为啥查询sqlite数据库时需要创建游标?
Posted
技术标签:
【中文标题】为啥查询sqlite数据库时需要创建游标?【英文标题】:Why do you need to create a cursor when querying a sqlite database?为什么查询sqlite数据库时需要创建游标? 【发布时间】:2011-09-13 04:07:30 【问题描述】:我对@987654321@(和一般的SQL)完全陌生,这完全让我难过。大量缺乏对cursor
objects 的描述(更确切地说,它们的必要性)似乎也很奇怪。
这个sn-p的代码是首选的做事方式:
import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()
这个不是,即使它工作得一样好并且没有(看似毫无意义的)cursor
:
import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
谁能告诉我为什么我需要cursor
?
这似乎是毫无意义的开销。对于脚本中访问数据库的每个方法,我都应该创建和销毁cursor
?
为什么不直接使用connection
对象?
【问题讨论】:
【参考方案1】:在我看来只是一个误用的抽象。 db 游标是一种抽象,用于数据集遍历。
来自Wikipedia article on subject:
在计算机科学和技术中,数据库游标是一个控件 允许遍历数据库中记录的结构。 光标与 遍历,例如数据库的检索、添加和删除 记录。遍历的数据库游标特性使得游标 类似于迭代器的编程语言概念。
还有:
游标不仅可以用于将数据从 DBMS 提取到 应用程序,还可以识别表中要更新的行或 删除。 SQL:2003 标准定义了定位更新和 为此目的定位删除 SQL 语句。这样的陈述确实 不要使用带有谓词的常规 WHERE 子句。相反,一个光标 标识行。光标必须已打开且已定位 通过 FETCH 语句在一行上。
如果您检查docs on Python sqlite module,您可以看到即使CREATE TABLE
语句也需要python 模块cursor
,因此它用于仅connection
对象就足够的情况 - 正如正确指出的那样由 OP。这种抽象不同于人们对 db 游标的理解,因此,用户的困惑/沮丧。不管效率如何,这只是概念上的开销。如果在文档中指出 python 模块 cursor
与 SQL 和数据库中的游标有点不同,那就太好了。
【讨论】:
+1 承认“传统”数据库游标和 Python 中用于数据库的游标之间(起初)非常令人困惑的区别 其实也可以直接create a table even without using a cursor。 游标的使用似乎与您提供的定义一致:“数据库游标是一种控制结构,可以遍历数据库中的记录”。例如c.execute('''SELECT * FROM users''')
返回一个迭代器,您可以在该迭代器上调用fetchall()
(或其他游标方法)。一些 SQL 查询返回空迭代器,但这应该是意料之中的,并不奇怪。【参考方案2】:
根据官方docsconnection.execute()
是一个非标准快捷方式,它创建了一个中间光标对象:
连接.执行 这是一个非标准的快捷方式,它通过调用 cursor() 方法创建一个游标对象,使用给定的参数调用游标的 execute() 方法,并返回游标。
【讨论】:
【参考方案3】:您需要一个游标对象来获取结果。您的示例有效,因为它是 INSERT
,因此您不会尝试从中获取任何行,但是如果您查看 sqlite3
docs,您会注意到连接上没有任何 .fetchXXXX
方法对象,因此如果您尝试在没有游标的情况下执行 SELECT
,您将无法获取结果数据。
游标对象允许您跟踪哪个结果集是哪个结果集,因为您可以在完成获取第一个结果之前运行多个查询。
【讨论】:
另外值得记住的是:PEP 249 没有在连接对象上定义execute
,这是一个sqlite3
扩展。
它仍然适用于 SELECT 语句:pastebin.com/5ZbhfEn7。原因是您没有在连接对象上调用任何 .fetchXXXX 方法,而是在连接的 .execute() 方法返回的对象上调用 .fetchXXXX 方法。
是的。但是,您最终会得到一个(看似)不必要的游标来查询数据库:p
显式使用游标是一个养成的好习惯,因为您将来可能会从事的项目不会自动提交。
很公平。感谢您的信息:)【参考方案4】:
12.6.8。使用 sqlite3 高效ly
12.6.8.1。使用快捷方式方法
使用 Connection 对象的 非标准
execute()
、executemany()
和executescript()
方法,您的代码可以写得更简洁,因为您不需要必须显式地创建(通常是多余的)Cursor 对象。相反,Cursor 对象是隐式创建的,并且这些快捷方法返回光标对象。这样,您可以执行 SELECT 语句并直接使用对 Connection 对象的单个调用对其进行迭代。
(sqlite3 documentation;强调我的。)
为什么不直接使用连接对象?
因为连接对象的那些方法是 nonstandard,即它们不是 Python Database API Specification v2.0 (PEP 249) 的一部分。
只要您使用 Cursor 对象的标准方法,您就可以确定,如果您切换到遵循上述规范的另一个数据库实现,您的代码将是完全可移植的。也许您只需要更改import
行。
但如果您使用connection.execute
,则切换可能不会那么简单。这就是您可能想要改用 cursor.execute
的主要原因。
但是,如果您确定不会切换,我会说使用 connection.execute
快捷方式并“高效”是完全可以的。
【讨论】:
【参考方案5】:它使我们能够通过同一个数据库连接拥有多个独立的工作环境。
【讨论】:
以上是关于为啥查询sqlite数据库时需要创建游标?的主要内容,如果未能解决你的问题,请参考以下文章
SQLite SELECT MAX() 查询返回 null 到游标?