Python MySQLdb:创建时出现语法错误 table
Python MySQLdb: Syntax Error when create table
代码很简单,我直接从控制台运行,同时,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', ))
错误仍然发生。
使用 .format 而不是 %s 这将允许您避免在查询中使用单引号。
例如:
my_sql_query = "CREATE TABLE {}".format(table_name)
mysql.execute(my_sql_query)
应该可以:)
你不小心打开了通往神秘冒险世界的大门。我的建议是:看之前不要关门。
问题是您正在尝试为占位符“在左侧”传递参数,但您与 MySQL 的接口仅适用于“右侧”。占位符用于 值 ,而不用于 字段名称 或 tables.
肤浅的解释
让我从另一个例子开始。
写入是合法的:
where field = %s
如果变量是一个字符串,你的符合 PEP 249 的接口将正确地解释它:把它想象成“在它周围加上引号”(尽管它不是它所做的,否则它会打开通往 SQL 注射;但这将说明这一点)。
在等式的右边。
但是如果你写:
where %s = 5
值为'my_field',它不会起作用,因为它在左侧。这不是界面的一部分。
正如您所说,如果您应用相同的逻辑,它会“在其周围加上引号”,因此您会得到:
where 'my_field' = 5
这显然没有意义,因为您在意想不到的地方得到了引述(注意:再次强调,这不是实际情况,但它说明了这一点)。它不起作用,但如果您遵循自己的逻辑,这些引用是您 应该 得到的。 有矛盾,所以明显有问题。
等等!
更深入的解释
了解 PEP 249 接口很重要,占位符的参数不会转换为字符串,然后放入字符串查询中。它们被翻译成它们的等价物(int 等)并在较低级别处理(我想在解析树或一些类似的结构中)。
已指定将参数转换为 值 的机制。它不是为变量 identifiers 设计的,例如 fields 或 tables(其中是一个更高级的用例)。
说“identifier is a variable”是个很高级的想法...带你进入higher-order programming的精彩世界.
可以扩展 PEP249 来做到这一点吗?理论上是的,但这不是一个开放和封闭的问题。
解决方案
与此同时,您只有一个选择:在 将字符串查询提供给 SQL 引擎之前 插入它。
sql = "CREATE TABLE %s like r_template;" % 'crawler'
我可以想象你周围的人恐惧的颤抖(不要打开那扇门!)。但据我所知,如果您 真的 想要一个变量 table 名称,那么您必须这样做。
到时候,你可能要问问自己为什么要有一个变量table名字?你这样做是为了其他事情的懒惰解决方法吗?在那种情况下,我会 return 走老路 而忘记使 table 或字段变量。
但是,我看到两个用例,其中 变量 table 或字段 是完全合法的:对于 数据库管理 或 构建数据库框架。
如果是这种情况,请小心使用字符串插值,以避免无意的 SQL 注入。您将不得不处理空格、特殊字符等不同的问题;一个好的做法是“引用”您的字段或 table 名称,例如在标准 MySQL:
`table accentuée`
然而,使用 ANSI 引用:
"table accentuée"
(如您所见,您 还差得远呢!)
还要小心去掉可能会导致解释器出错的东西,例如分号。
无论如何,如果你想这样做,你需要航行到海岸视线之外,直接朝向日落。您正处于左侧英雄之旅的门槛上。你会享受冒险,只要你接受没有救生员来救你的事实。
代码很简单,我直接从控制台运行,同时,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', ))
错误仍然发生。
使用 .format 而不是 %s 这将允许您避免在查询中使用单引号。 例如:
my_sql_query = "CREATE TABLE {}".format(table_name)
mysql.execute(my_sql_query)
应该可以:)
你不小心打开了通往神秘冒险世界的大门。我的建议是:看之前不要关门。
问题是您正在尝试为占位符“在左侧”传递参数,但您与 MySQL 的接口仅适用于“右侧”。占位符用于 值 ,而不用于 字段名称 或 tables.
肤浅的解释
让我从另一个例子开始。
写入是合法的:
where field = %s
如果变量是一个字符串,你的符合 PEP 249 的接口将正确地解释它:把它想象成“在它周围加上引号”(尽管它不是它所做的,否则它会打开通往 SQL 注射;但这将说明这一点)。
在等式的右边。
但是如果你写:
where %s = 5
值为'my_field',它不会起作用,因为它在左侧。这不是界面的一部分。
正如您所说,如果您应用相同的逻辑,它会“在其周围加上引号”,因此您会得到:
where 'my_field' = 5
这显然没有意义,因为您在意想不到的地方得到了引述(注意:再次强调,这不是实际情况,但它说明了这一点)。它不起作用,但如果您遵循自己的逻辑,这些引用是您 应该 得到的。 有矛盾,所以明显有问题。
等等!
更深入的解释
了解 PEP 249 接口很重要,占位符的参数不会转换为字符串,然后放入字符串查询中。它们被翻译成它们的等价物(int 等)并在较低级别处理(我想在解析树或一些类似的结构中)。
已指定将参数转换为 值 的机制。它不是为变量 identifiers 设计的,例如 fields 或 tables(其中是一个更高级的用例)。
说“identifier is a variable”是个很高级的想法...带你进入higher-order programming的精彩世界.
可以扩展 PEP249 来做到这一点吗?理论上是的,但这不是一个开放和封闭的问题。
解决方案
与此同时,您只有一个选择:在 将字符串查询提供给 SQL 引擎之前 插入它。
sql = "CREATE TABLE %s like r_template;" % 'crawler'
我可以想象你周围的人恐惧的颤抖(不要打开那扇门!)。但据我所知,如果您 真的 想要一个变量 table 名称,那么您必须这样做。
到时候,你可能要问问自己为什么要有一个变量table名字?你这样做是为了其他事情的懒惰解决方法吗?在那种情况下,我会 return 走老路 而忘记使 table 或字段变量。
但是,我看到两个用例,其中 变量 table 或字段 是完全合法的:对于 数据库管理 或 构建数据库框架。
如果是这种情况,请小心使用字符串插值,以避免无意的 SQL 注入。您将不得不处理空格、特殊字符等不同的问题;一个好的做法是“引用”您的字段或 table 名称,例如在标准 MySQL:
`table accentuée`
然而,使用 ANSI 引用:
"table accentuée"
(如您所见,您 还差得远呢!)
还要小心去掉可能会导致解释器出错的东西,例如分号。
无论如何,如果你想这样做,你需要航行到海岸视线之外,直接朝向日落。您正处于左侧英雄之旅的门槛上。你会享受冒险,只要你接受没有救生员来救你的事实。