代码非常简单,我只是直接从控制台运行它,同时, spider.table_name =' crawler'
import MySQLdb
import scrapy
print (spider.table_name) # >> 'crawler'
db = MySQLdb.connect(........)
db.set_character_set('utf8')
mysql = db.cursor()
sql = "CREATE TABLE %s like r_template;"
mysql.execute(sql, (spider.table_name, ))
db.commit()
但是我得到了语法错误:
ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''crawler' like r_template' at line 1")
似乎正在执行的实际sql语句是:
CREATE TABLE 'crawler' like r_template
如何单引号''产生的?如何防止它发生?
然后,我尝试了更简单的方法:
mysql.execute(sql, ('crawler', ))
mysql.execute("CREATE TABLE %s like r_template", ('crawler', ))
错误仍然发生。
答案 0 :(得分:2)
你不小心打开了一扇神秘冒险世界的大门。我的建议是:在看之前不要关上那扇门。
问题是你正试图传递占位符“在左侧”的参数,但你的MySQL界面只适用于“右侧” 。占位符用于值,而不是字段名称或表格。
让我从另一个例子开始。
写作是合法的:
where field = %s
如果变量是一个字符串,你的PEP 249兼容接口将正确解释它:把它想象为“在它周围加上引号”(虽然它不是它的作用,否则它将打开SQL注入的大门;但这将说明这一点。
这是在平等的右侧。
但如果你写:
where %s = 5
值为'my_field',它不起作用,因为它位于左侧。这不是界面的一部分。
正如你所说,如果你应用相同的逻辑,它会“在它周围加上引号”,所以你会得到:
where 'my_field' = 5
它显然没有意义,因为你得到了你没想到它们的引用(警告:再次,这不是发生了什么,但它说明了这一点)。它不起作用,但是如果你遵循自己的逻辑,那些引用就是你应该得到的。 存在矛盾,所以有些事情显然是错误的。
但是等等!
重要的是要理解,使用PEP 249接口时,占位符的参数不会转换为字符串,然后放入字符串查询中。它们被翻译成它们的等价物(int等)并在较低级别处理(在解析树或类似结构中,我想)。
已指定机制将参数转换为值。它不是为变量标识符而设计的,例如字段或表格(这是一种更高级的用例)。
说“标识符是一个变量”是一个非常先进的想法... 我带你进入higher-order programming的精彩世界。
PEP249可以扩展吗?理论上是的,但这不是一个开放和封闭的问题。
与此同时,您只剩下一个选项:在>>之前插入字符串查询,然后将其提供给SQL引擎。
sql = "CREATE TABLE %s like r_template;" % 'crawler'
我可以想象你身边的人会发出恐怖的颤抖(不要打开那扇门!)。但据我所知,如果你真的希望拥有一个变量表名,那就是你必须要做的。
此时,您可能想问自己为什么要使用变量表名?你是否以其他方式做了一个懒惰的解决方法?在这种情况下,我会回到常规路径并忘记使表或字段变量。
但是,我看到两个用例变量表或字段完全合法:数据库管理或构建数据库框架
如果是这种情况,只需谨慎使用字符串插值,以避免无意的SQL注入。你将不得不处理与空白,特殊字符等不同的问题;一个好的做法是“引用”你的字段或表名,例如在标准的MySQL中:
`tableaccentuée`
然而,使用ANSI引用:
“tableaccentuée”
(如你所见,你 远远没有!)
另外要小心剥掉可能会解散翻译的东西,比如分号。
无论如何,如果你想这样做,你需要远离海岸的视线,直奔日落。你正处于英雄前往左侧之旅的门槛上。您将享受冒险,只要您接受没有救生员来救你。
答案 1 :(得分:0)
使用.format代替%s,这样可以避免查询中的单引号。 例如:
my_sql_query = "CREATE TABLE {}".format(table_name)
mysql.execute(my_sql_query)
这应该有效:)