我有一个单一的任务,我正在实现一个用户通过网页进行交互的数据库。目标是根据一些标准搜索书籍。这是一个更大项目中的一个模块。
我想让用户能够选择他们想要的标准和顺序,但以下似乎不起作用:
cursor.execute("SELECT * FROM Books WHERE ? REGEXP ? ORDER BY ? ?", [category, criteria, order, asc_desc])
我无法理解为什么,因为我去的时候
cursor.execute("SELECT * FROM Books WHERE title REGEXP ? ORDER BY price ASC", [criteria])
我得到了完整的结果。有没有办法解决这个问题而不诉诸注射?
数据组织在一个表中,其中书的ISBN是主键,每行有许多列,例如书的标题,作者,出版商等。应允许用户选择任何这些列和进行搜索。
答案 0 :(得分:1)
通常,SQL引擎仅支持 values 上的参数,而不支持表,列等的名称。对于sqlite本身和Python的sqlite模块也是如此。
这背后的基本原理部分是历史性的(传统的笨拙的数据库API有明确的bind
调用,你必须说明你绑定哪个列号与哪种类型的值等等,但主要是因为没有参数化价值的理由很充分。
一方面,您无需担心表名和列名的引用或类型转换。另一方面,一旦你开始让最终用户来源的文本指定一个表或列,就很难看出他们可以做些什么其他的伤害。
另外,从性能的角度来看(如果您阅读sqlite docs - 请参阅第3.0节 - 您会注意到他们专注于参数绑定作为性能问题,而不是安全问题),数据库引擎可以在给定不同的值时重用已准备好的优化查询计划,但在给定不同的列时则不能。
那么,你能做些什么呢?
好吧,动态生成SQL字符串是一种选择,但不是唯一的选择。
首先,这种事情往往是数据模型破碎的标志,需要进一步规范化。也许你应该有一个BookMetadata
表,你有很多行 - 每个行都有一个字段名称和一个值 - 每个Book
?
其次,如果你想要的东西在概念上被规范化,就这个代码而言,但实际上是非规范化的(无论是为了效率,还是因为某些其他代码,不应该被标准化)...功能很棒。 create_function
一个包装器,您可以在execute
时将参数传递给该函数。