微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 sqlite3 DB_API qmark 和命名样式在“select where”查询中不起作用?

如何解决为什么 sqlite3 DB_API qmark 和命名样式在“select where”查询中不起作用?

假设我有一个包含表 users 和一行的数据库

ID = 0,name = 'myName'

我可以使用以下任一方法获取 ID 值(假设我已连接):

cursor.execute("""SELECT ID FROM users WHERE %s = %s""" % ('name','myName'))
print(cursor.fetchone())

cursor.execute("""SELECT ID FROM users WHERE {} = {}""".format('name','myName'))
print(cursor.fetchone())

根据 the documentation 两者都工作得很好,但都是不好的做法。

文档建议对具有可变输入的查询使用 qmark 或命名样式。在 SELECT * FROM myDatabase WHERE ? = ? 查询中使用建议的样式时会出现问题。


qmark 样式:

cursor.execute("""SELECT ID FROM users WHERE ? = ?""",('name','myName'))
print(cursor.fetchone())

命名样式

cursor.execute("""SELECT ID FROM users WHERE :column = :cell""",{'column': 'name','cell':'myName'})
print(cursor.fetchone())

使用后一种样式会导致 None 返回。在 INSERT 的上下文中使用 qmark 或命名样式时,如文档中的示例中使用的那样,它确实按预期工作。

(澄清一下,对于 qmark 样式,为每个 ? 或整个 ? = ? 添加括号不会改变结果。对每个 ? 使用括号并使用附加参数会导致execute() 由于给出的参数过多而导致故障。)

是什么导致了这种行为?是否可以在 SELECT...WHERE ? = ? 查询中使用 qmark 或命名样式?

解决方法

参数替换用于,而不是标识符(列和表的名称等)。 RDBMS 对引用值和 identifiers 有不同的规则。对标识符使用参数替换占位符会导致标识符被错误引用,例如

cur.execute('SELECT * FROM tbl WHERE ? = ?',('col1',42))

最终为

SELECT * FROM tbl WHERE 'col1' = 42

注意 col1 周围的单引号,这导致它被评估为字符串,而不是列名。

如果您想在查询中使用动态标识符和值,请使用字符串格式作为标识符和参数替换值。例如,对标识符使用双引号

cur.execute('SELECT * FROM tbl WHERE "{}" = ?'.format('col1'),(42,))

这是导致错误的字符串格式示例

>>> conn = sqlite3.connect(':memory:')
>>> conn.execute('create table tbl (col1 date)')
<sqlite3.Cursor object at 0x7f56abcf1ce0>
>>> cur = conn.cursor()
>>> cur.execute('INSERT INTO tbl (col1) VALUES(?)',('2021-05-01',))
<sqlite3.Cursor object at 0x7f56abc8f030>
>>> cur.execute('INSERT INTO tbl (col1) VALUES(%s)' % '2021-05-01')
<sqlite3.Cursor object at 0x7f56abc8f030>
>>> conn.commit()
>>> cur.execute('SELECT col1 FROM tbl WHERE %s = %s' % ('col1','2021-05-01'))
<sqlite3.Cursor object at 0x7f56abc8f030>
>>> for row in cur:print(row)
... 
(2015,)

INSERTSELECT 语句中使用字符串格式时,日期被计算为算术表达式,导致存储和检索错误值。像这样的错误很烦人,但使用字符串格式也会让您的应用程序受到 SQL 注入攻击,这可能会产生更严重的后果。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?