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

18 投票
2 回答
5853 浏览
提问于 2025-04-17 10:07

我正在使用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))

不过我遇到的错误信息并不太有帮助(sqlite3.OperationalError: near "?": syntax error),但我明白了:Pysqlite不喜欢这样使用占位符。

有没有人能告诉我这是怎么回事,以及正确的做法是什么?

2 个回答

2

正如@unutbu所说,表名和列名是不能用占位符的。我建议你继续现在的做法,但要把表名加上引号,这样可以保护自己,避免遇到一些奇怪的表名或列名。

SQL标准对反引号(`)的使用有什么说明?这篇文章已经在一定程度上解释了这个问题,尽管那里的观点有所不同,但我认为在你的情况下,加引号是个好主意。

23

你不能用占位符来表示列名或表名。我没有权威的来源来证明这一点——我只是通过尝试和失败得出的这个结论。不过,这样想也有道理:

  • 如果列和表可以用参数来表示,那在获取数据之前准备(执行)SQL语句就没什么意义了,因为语句的所有部分都可以被替换。
  • 我不太确定pysqlite1的情况,但MySQLdb会自动给所有字符串参数加上引号。列名和表名是不应该加引号的。如果驱动程序需要判断一个占位符是代表列名或表名,还是需要加引号的值,这样会让解析变得复杂。

总之,你找到了正确的方法——使用字符串格式化。

c.execute('SELECT {} FROM {} WHERE id=?'.format(column, table), row))

1并不是所有的驱动程序都会给参数加引号——oursql就不会,因为它是把SQL和参数分开发送到服务器的。

撰写回答