Python MySQLdb转义字符:查询在MySQL中有效,但不在python MySQLdb中

时间:2013-08-29 13:23:23

标签: python mysql sql pandas mysql-python

我正试图通过Python的MySQLdb库将数据从Pandas(从CSV导入)传递到MySQL数据库。当字面反斜杠发挥作用时,我遇到了麻烦。我从原始输入中转义单个反斜杠,因此Python知道它们是字面反斜杠,而不是后续字符的转义。但是当我尝试执行INSERT查询时,MySQLdb表示存在语法错误。但这里令人困惑的是令人沮丧的部分:如果我将确切的字符串复制/粘贴到MySQL中,它会毫无问题地执行。

我试图保留数据&结构尽可能接近实际数据,但改为保留隐私。请注意,在第一行的SourceSystemID列的末尾和第二行的MiddleInitial列中有两个类似的有问题的值。

In [39]: test
Out[39]: 

  ehrSystemID SourceSystemID LastName FirstName MiddleInitial  Sex  
0   fakePlace           ABC\      NaN       NaN           NaN  NaN   
1   fakePlace            XYZ    Smith      John             \    M   
          npi  deaNumber LicenseNumber ProvSpecialty  dob  
0  1234567890  AB1234567       !123456      Internal  NaN  
1         NaN        NaN       B123456      Internal  NaN  

这些行的值转换为字符串以附加到INSERT语句的末尾(请注意,所有MySQL列都将是varchar,因此所有值都包含在单引号中)

In [40]: testVals
Out[40]: "('fakePlace', 'ABC\\', '', '', '', '', '1234567890', 'AB1234567', '!123456', 'Internal', ''), ('fakePlace', 'XYZ', 'Smith', 'John', '\\', 'M', '', '', 'B123456', 'Internal', '')"

我传递给MySQLdb的命令导致错误:

In [41]: testCmd1
Out[41]: "INSERT INTO source_providers (ehrSourceID, sourceSystemID, nameLast, nameFirst, nameMiddle, sex, npiRaw, dea, licenseNumber, specialty1, dobRaw) VALUES ('fakePlace', 'ABC\\', '', '', '', '', '1234567890', 'AB1234567', '!123456', 'Internal', ''), ('fakePlace', 'XYZ', 'Smith', 'John', '\\', 'M', '', '', 'B123456', 'Internal', '')"

In [42]: db.Cur.execute(testCmd1)
---------------------------------------------------------------------------
ProgrammingError                          Traceback (most recent call last)
<ipython-input-42-32fe62e740d8> in <module>()
----> 1 db.Cur.execute(testCmd1)

/Library/Python/2.7/site-packages/MySQL_python-1.2.4b4-py2.7-macosx-10.8-intel.egg/MySQLdb/cursors.pyc in execute(self, query, args)
    200             del tb
    201             self.messages.append((exc, value))
--> 202             self.errorhandler(self, exc, value)
    203         self._executed = query
    204         if not self._defer_warnings: self._warning_check()

/Library/Python/2.7/site-packages/MySQL_python-1.2.4b4-py2.7-macosx-10.8-intel.egg/MySQLdb/connections.pyc in defaulterrorhandler(***failed resolving arguments***)
     34     del cursor
     35     del connection
---> 36     raise errorclass, errorvalue
     37 
     38 re_numeric_part = re.compile(r"^(\d+)")

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 '1234567890', 'AB1234567', '!123456', 'Internal', ''), ('fakePlace', 'XYZ', 'Smit' at line 1")

直接在MySQL中成功执行确切的命令:

mysql> INSERT INTO source_providers (ehrSourceID, sourceSystemID, nameLast, nameFirst, nameMiddle, sex, npiRaw, dea, licenseNumber, specialty1, dobRaw) VALUES ('fakePlace', 'ABC\\', '', '', '', '', '1234567890', 'AB1234567', '!123456', 'Internal', ''), ('fakePlace', 'XYZ', 'Smith', 'John', '\\', 'M', '', '', 'B123456', 'Internal', '');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

当字符串传递给MySQL API时会发生什么?如何避免过滤掉有问题的行并单独手动插入?这涉及数万行,因此我专注于自动化流程。

感谢。

1 个答案:

答案 0 :(得分:3)

事实证明,混淆是Python如何打印查询字符串,并结合我自己的代码中的错误。 首先,错误:我错误地使用str.replace()用转义的双精度替换单个文字反斜杠:

sqlCmd.replace('\\', '\\\\') 

因此,当Python在打印字符串时显示双斜杠时,我认为它已成功替换了单斜杠。正确的代码(如果读取此内容的任何人犯同样的错误)是:

sqlCmd = sqlCmd.replace('\\', '\\\\')

第二个混淆的原因是Python解释器使用__repr__() 自动插入一个转义反斜杠来显示但是这个转义反斜杠实际上并不在原始字符串中< / em>的。 Python假设你足够聪明,可以知道这一点。事实证明我不是。 ; - )

另一个stackoverflow问题here的答案中提供了__repr__()和反斜杠的简短附加说明。