将 Python 列表(JSON 或其他)插入 MySQL 数据库

Posted

技术标签:

【中文标题】将 Python 列表(JSON 或其他)插入 MySQL 数据库【英文标题】:Insert Python List (JSON or otherwise) into MySQL databse 【发布时间】:2012-08-31 14:02:03 【问题描述】:

所以我在 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://***.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 单元中?

输出here

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

你需要让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))

请参阅Python DB API 2.0 spec 了解有关参数化 SQL 的(一些)更多详细信息。每个数据库适配器都记录了确切支持的参数格式,因此也要检查一下。例如,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)。

【讨论】:

谢谢,这完全有帮助。我选择 jsbueno 的答案作为已接受的答案,因为在 sql_input 中插入了一些参数,而在执行命令期间传入了其他参数,这对我来说会导致 TypeError(TypeError:并非所有参数都在字符串格式化期间转换)。但是,再次感谢,这绝对为我指明了正确的方向。 这听起来像是参数数量和你传入的值不匹配。【参考方案3】:

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

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

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

大多数 python db api 使用类似于此的占位符语法:

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

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

有些也允许使用字典:

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

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

【讨论】:

【参考方案4】:

您只是以错误的形式调用 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 文件中而不是在自动生成的文件中使用所有这些疯狂的硬编码数字,我敢说您的项目无论如何都注定要失败。

【讨论】:

【参考方案5】:

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

永远、永远、永远不要这样做;

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

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

相反,这样做:

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

并让MySql接口整理转义。

【讨论】:

以上是关于将 Python 列表(JSON 或其他)插入 MySQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何优化使用 PHP 或 Mysql 或 Laravel 将 12K 的 JSON 插入数据库

将包含许多嵌套对象的JSON文件保存到列表中

python中列表中的JSON或CSV

如何在android中将arraylist或vector插入SQLite数据库?

JSON / MySQL:列表索引必须是整数或切片,而不是 str

如何根据其他下拉选择将本地 Json 加载到 Flutter DropDown?