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))
不过我遇到的错误信息并不太有帮助(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和参数分开发送到服务器的。