4

所以我在Python中有一堆数组数据。好吧,我有一个列表列表。我正在尝试将此数组存储到 MySQL 数据库中的单个单元格中。我尝试使用 JSON 来序列化我的数据,但也许我不明白 JSON 是如何工作的。

所以在连接到我的数据库后:(我已经尝试了上游和下游的 LONGTEXT 和 LONGBLOB 数据类型

cur = con.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS 963168MBV17A(Id INT AUTO_INCREMENT PRIMARY KEY, Rev INT, Part VARCHAR(15), SN INT(7), Date DATE, Time TIME, Iterations INT(3), Upstream LONGBLOB, Downstream LONGBLOB, ResultList LONGTEXT, Result CHAR(1), Report LONGBLOB)")

我将我的列表列表称为 upstream_data 和downstream_data 并执行以下操作:

export_upstream = json.dumps(upstream_data)
export_downstream = json.dumps(downstream_data)

然后我执行 SQL 命令:

cur = con.cursor()    
sql_input = "INSERT INTO 963168MBV17A(Rev, Part, SN, Iterations, Date, Time, Upstream, Downstream, ResultList, Result, Report) VALUES('503', '100-120970-0031', '1594539', '%s', '%s', '%s', '%s', '%s', 0, P, 0" %(export_date, export_time, export_numtests, export_upstream, export_downstream)
cur.execute(sql_input)

参考 Mordi 的答案(http://stackoverflow.com/questions/4251124/inserting-json-into-mysql-using-python),我什至尝试过:

export_upstream = json.dumps(json.dumps(upstream_data))
export_downstream = json.dumps(json.dumps(downstream_data))

但无论如何我最终都会遇到错误:

Traceback (most recent call last):
  File "P:\Projects\testing database\scrap\test.py", line 83, in <module>
    cur.execute(sql_input)
  File "C:\Python27\lib\site-packages\MySQLdb\cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
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 '' at line 1")

此外,当我做一个

print "about to execute(%s)" % sql_input

我看到 JSON 对象显示为一个长字符串,到处都是单引号(用于列表,在外部表示字符串)。当我执行 json.dumps(json.dumps(upstream_data)) 时,内部引号变为双引号 "" 并以 \ 字符开头。尽管如此,我还是遇到了同样的错误。

有任何想法吗?如果没有,有没有更好的方法将 Python 数组/列表数据存储到单个 MySQL 单元中?

在这里输出

4

5 回答 5

6

你需要让 MySQL 库为你做参数处理;这有一个额外的好处是让 MySQL 准备你的语句,使重复插入也更快:

cur = con.cursor()    
sql_input = "INSERT INTO 963168MBV17A(Rev, Part, SN, Iterations, Date, Time, Upstream, Downstream, ResultList, Result, Report) VALUES('503', '100-120970-0031', '1594539', ?, ?, ?, ?, ?, 0, P, 0"
cur.execute(sql_input, (export_date, export_time, export_numtests, export_upstream, export_downstream))

有关参数化 SQL 的(一些)更多详细信息,请参阅Python DB API 2.0 规范。每个数据库适配器都记录了确切支持的参数格式,因此也要检查一下。例如,MySQLdb 模块模仿 python 字符串格式化语法,并%s用作占位符:

sql_input = "INSERT INTO 963168MBV17A(Rev, Part, SN, Iterations, Date, Time, Upstream, Downstream, ResultList, Result, Report) VALUES('503', '100-120970-0031', '1594539', %s, %s, %s, %s, %s, 0, P, 0"

其他可能的参数选项是数字(:1, :2等)、名称(:foo, :bar)或其他形式的 Python 字符串格式,命名格式说明符:(%(foo)s, %(bar)s)。

于 2012-09-06T17:36:57.527 回答
1

您只是以错误的形式调用 DB API,如果您像这样替换您的参数,您将负责自己转义数据中的引号和双引号。

这不仅会给你带来你遇到的错误(而且你很幸运),因为这也允许 SQL 注入的危险攻击。

Python 的数据库 API 是从头开始设计的,以避免发生此类攻击的可能性,它通过让调用cursor.execute为您执行字符串替换来简单地做到这一点。然后它将向您的字符串添加必要的转义。所以,而不是这样做:

sql_input = "INSERT INTO 963168MBV17A(Rev, Part, SN, Iterations, Date, Time, Upstream, Downstream, ResultList, Result, Report) VALUES('503', '100-120970-0031', '1594539', '%s', '%s', '%s', '%s', '%s', 0, P, 0" %(export_date, export_time, export_numtests, export_upstream, export_downstream)
cur.execute(sql_input)

sql_input = "INSERT INTO 963168MBV17A(Rev, Part, SN, Iterations, Date, Time, Upstream, Downstream, ResultList, Result, Report) VALUES(%s, %s,%s, %s, %s, %s, %s, %s, %s, %s, %s" 
cur.execute(sql_input, [503, '100-120970-0031', '1594539', export_date, export_time, export_numtests, export_upstream, export_downstream, 0, "P", 0] )

——不过,如果你在你的 SOURCE 文件中需要所有那些疯狂的硬编码数字,而不是在自动生成的文件中,我敢说你的项目无论如何都注定要失败。

于 2012-09-06T17:38:10.857 回答
1

我在您的代码中看到的第一个问题是:

sql_input = "INSERT INTO table (column) VALUES('%s');" % ( data )

你永远不应该这样做——你正在使用字符串插值,它不能保护你免受 SQLinjection 或格式错误的 sql 的影响。

大多数 python db apis 使用类似于以下的占位符语法:

sql = "INSERT INTO table (column) VALUES( %s );"
values = (data,)
cur.execute(sql,values)

请注意,您分别传入语句和值。API 处理转义和格式化。

有些也允许使用dicts:

sql = "INSERT INTO table (column) VALUES( %(id)s );"
values = { 'id': 1 )
cur.execute(sql,values)

阅读如何正确使用您的数据库 api - 这是您最大的问题,并且可能会导致您的所有其他问题。

于 2012-09-06T17:39:21.507 回答
1

您可能会尝试的一件事是使用 SQLAlchemy 的SQL 表达式生成,它将为您处理所有转义等,另外还可以让您避免处理许多安全漏洞(至少在插入 SQL 数据库等方面)。它参数化查询,而不是像您尝试做的那样进行内联字符串插值。

于 2012-09-06T17:47:37.517 回答
0

我预计问题是由于转义 SQL 命令,或者更确切地说是缺少相同的。

永远,永远,永远这样做;

cursor.execute("INSERT INTO whatever VALUES (%s)" % "foo")

除了您看到的问题之外,如果您在那里传递用户输入是不安全的(如果您不知道原因,请查找“Little Johnny Tables”)。

相反,请执行以下操作:

cursor.execute("INSERT INTO whatever VALUES (%s)", ["foo"])

并让MySql接口整理转义。

于 2012-09-06T17:36:22.920 回答