SQLite中的变量表名
问题:有没有办法用变量来当表名,而不需要使用字符串构造器?
信息:
我现在正在做一个项目,目的是整理我一个星星模拟的数据。为此,我把所有数据都加载到一个sqlite数据库里。这个方法效果还不错,但我决定要让我的数据库更加灵活、高效和易用。我计划以后在模拟中添加一些小行星,并想为每颗星星建立一个表。这样的话,我就不用在一个有2000万个小行星的表里去查找每个太阳系里的1000到4000个小行星了。
有人告诉我,使用字符串构造器不好,因为这样会让我容易受到SQL注入攻击。虽然在这里这不是个大问题,因为只有我一个人能访问这些数据库,但我还是想遵循最佳实践。而且这样的话,如果我以后做一个类似的项目,开放给公众,我就知道该怎么做了。
目前我在这样做:
cursor.execute("CREATE TABLE StarFrame"+self.name+" (etc etc)")
这个方法有效,但我想做得更像:
cursor.execute("CREATE TABLE StarFrame(?) (etc etc)",self.name)
虽然我知道这可能是不可能的。不过我也能接受类似这样的做法:
cursor.execute("CREATE TABLE (?) (etc etc)",self.name)
如果这根本不可能,我会接受这个答案,但如果有人知道怎么做到,请告诉我。 :)
我用的是python编程。
10 个回答
我建议不要把数据分成多个表。如果你在星级这一列上创建一个索引,那么你就能很高效地访问这些数据,不会遇到任何问题。
对于那些想把表名当作变量的人,我从另一个回答中找到了这个方法,链接在这里:
内容如下,来自mhawke的引用:
你不能用参数替换来设置表名。你需要自己把表名加到查询字符串里。可以这样做:
query = 'SELECT * FROM {}'.format(table)
c.execute(query)
需要注意的是,表名的来源。如果这个表名来自不可信的地方,比如用户输入,那么你需要验证这个表名,以避免可能的SQL注入攻击。一个方法是构建一个参数化查询,从数据库目录中查找表名:
import sqlite3
def exists_table(db, name):
query = "SELECT 1 FROM sqlite_master WHERE type='table' and name = ?"
return db.execute(query, (name,)).fetchone() is not None
很遗憾,表格不能作为参数替换的对象(虽然我没有找到确凿的来源,但在一些网络论坛上见过这样的说法)。
如果你担心注入问题(你可能应该担心),可以写一个函数来清理字符串,然后再传递给数据库。因为你只需要一个表名,所以只要接受字母和数字就可以了,去掉所有的标点符号,比如 )(][;,
和空格。简单来说,就是只保留 A-Z a-z 0-9
这些字符。
def scrub(table_name):
return ''.join( chr for chr in table_name if chr.isalnum() )
scrub('); drop tables --') # returns 'droptables'