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 设计的,例如 fieldstables(其中是一个更高级的用例)。

说“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"

(如您所见,您 还差得远呢!)

还要小心去掉可能会导致解释器出错的东西,例如分号。

无论如何,如果你想这样做,你需要航行到海岸视线之外,直接朝向日落。您正处于左侧英雄之旅的门槛上。你会享受冒险,只要你接受没有救生员来救你的事实。