pysqlite:占位符替换列名或表名?

por*_*uod 15 python sql sqlite pysqlite

使用pysqlite我正在制作一个程序来处理某些数据.同样种类的操作是在多个表和列类似领域完成的,所以我想我可以参数化的SQL语句,如下所示:

def foo():
  column = 'c'
  table = 't'
  row = 1
  # preferred approach, gives syntax error
  c.execute('SELECT ? FROM ? WHERE id=?', (column, table, row))
  # sanity check, works fine
  c.execute('SELECT c FROM t WHERE id=?', (row))
  # workaround, also works, but is this the right way?
  c.execute('SELECT % FROM % WHERE id=?' % (column, table), row))
Run Code Online (Sandbox Code Playgroud)

我得到的错误是不是非常有帮助(sqlite3.OperationalError: near "?": syntax error),但我得到了这一点:在以这种方式使用的占位符Pysqlite并不领情.

谁能指出这里发生了什么以及正确的做法?

unu*_*tbu 18

您根本无法使用占位符作为列名或表名.我没有这方面的权威性引用 - 我只是通过尝试和失败来"知道"这一点.但它有一定道理:

  • 如果可以对列和表进行参数化,那么execute在获取之前准备(-ing)SQL语句的目的很小,因为可以替换语句的所有部分.
  • 我不确定pysqlite 1,但MySQLdb会自动引用所有字符串参数.不应引用列名和表名.因此,如果必须确定占位符是表示列名还是表名,而不是需要引用的值,则会使驱动程序所需的解析复杂化.

简而言之,您找到了正确的方法 - 使用字符串格式化.

c.execute('SELECT {} FROM {} WHERE id=?'.format(column, table), row))
Run Code Online (Sandbox Code Playgroud)

1并非所有驱动程序都引用参数 - oursql不是,因为它将SQL和参数分别发送到服务器.

  • @berkelem:它很容易受到 SQL 注入的攻击。不幸的是,由于列名和表名不可参数化,因此无法避免字符串格式化。[使用白名单](https://phpdelusions.net/sql_injection#whitelist) 是这里的最佳实践。 (2认同)