SQLite参数替换问题

cry*_*ice 58 python sqlite

使用SQLite3和Python 2.5,我试图遍历列表并根据项目的名称从数据库中提取项目的权重.

我试过用"?" 建议参数替换以防止SQL注入,但它不起作用.例如,当我使用:

for item in self.inventory_names:
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", item)
    self.cursor.close()
Run Code Online (Sandbox Code Playgroud)

我收到错误:

sqlite3.ProgrammingError:提供的绑定数量不正确.当前语句使用1,并且提供了8.

我相信这是由数据库的初始创建引起的; 我制作的实际创建数据库的模块确实有8个绑定.

cursor.execute("""CREATE TABLE Equipment 
    (id INTEGER PRIMARY KEY, 
    name TEXT,
    price INTEGER, 
    weight REAL, 
    info TEXT, 
    ammo_cap INTEGER, 
    availability_west TEXT,
    availability_east TEXT)""")
Run Code Online (Sandbox Code Playgroud)

但是,当我对每个项目名称使用不太安全的"%s"替换时,它可以正常工作.像这样:

for item in self.inventory_names:
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = '%s'" % item)
    self.cursor.close()
Run Code Online (Sandbox Code Playgroud)

当我只调用一个绑定时,我无法弄清楚为什么它认为我有8个绑定.我该如何解决?

dda*_*daa 132

Cursor.execute()方法期望序列作为第二参数.您提供的字符串恰好是8个字符长.

请改用以下表格:

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", [item])
Run Code Online (Sandbox Code Playgroud)

Python库参考:sqlite3 Cursor Objects.


小智 57

我花了半天的时间试图找出为什么这样的东西会给我一个错误:

cursor.execute("SELECT * from ? WHERE name = ?", (table_name, name))
Run Code Online (Sandbox Code Playgroud)

只是发现表名不能参数化.希望这会帮助其他人节省一些时间.

  • 对于用户输入确定表的情况,我从dict中提取表的名称,如果输入的内容是意外的,则引发异常.可能不是_best_方式,但似乎不太可能导致SQL注入. (6认同)
  • 您可以执行以下操作:`cursor.execute("SELECT * from %s WHERE name = ?" % table_name, (name,))`,尽管这可能会使您的程序容易受到 SQL 注入攻击。 (3认同)

jgt*_*ime 22

其中的参数cursor.execute表示您需要在数据库中插入的值应该是元组(序列).但是请考虑这个例子,看看发生了什么:

>>> ('jason')
'jason'

>>> ('jason',)
('jason',)
Run Code Online (Sandbox Code Playgroud)

第一个示例改为求值为字符串; 所以表示单值元组的正确方法与第二次评估一样.无论如何,下面的代码来修复你的错误.

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", (item,))
Run Code Online (Sandbox Code Playgroud)

同时将cursor.execute值参数作为字符串给出(这就是你正在做的事情)会导致示例中的第一次评估,并导致你得到的错误.

  • 我认为这应该是公认的答案 (2认同)

Mik*_*e T 5

sqlite3模块支持两种参数占位符:

qmark风格

使用一个或多个?标记每个参数的位置,并提供参数列表或元组。例如:

curs.execute("SELECT weight FROM Equipment WHERE name = ? AND price = ?",
             ['lead', 24])
Run Code Online (Sandbox Code Playgroud)

命名风格

:par为每个命名参数使用占位符,并提供一个字典。例如:

curs.execute("SELECT weight FROM Equipment WHERE name = :name AND price = :price",
             {name: 'lead', price: 24})
Run Code Online (Sandbox Code Playgroud)

命名样式参数的优点是您无需担心参数的顺序,并且每个:par都可以在大型/复杂的 SQL 查询中多次使用。