【问题标题】:Syntax error using INSERT INTO statement with MySQL-Python使用带有 MySQL-Python 的 INSERT INTO 语句的语法错误
【发布时间】:2025-12-03 06:55:02
【问题描述】:

我正在尝试使用以下 SQL 语法使用来自文本文件的每一行的值填充 MySQL 数据库中的表:

INSERT INTO Table SET
  fieldname1 = "value1",
  fieldname2 = "value2",
  fieldname3 = "value3";

我使用嵌套的for 循环来打印一个字符串(名为SQL3),该字符串对文本文件的每一行都使用相同的字段名称,试图以正确的方式处理语法。好像我已经接近了,但它仍然向我抛出一个 SQL 语法错误,而且我似乎对可能发生的事情视而不见。由于这是第一次尝试通过 Python 连接到数据库,因此可能还隐藏着更多问题。

希望有人可以帮助找到问题。是否缺少一些重要信息?

这是代码:

import MySQLdb 

fieldNames = """Org_rowNr_countsheet
Orig_row_10604
pt3
pt3_ensembl_id
status
pt2_meth
pt3_meth
pt2_kegg_id
pt2_uniprotID
pt3_kegg_hit
pt3_uniprot
pt2_contig
pt2_start
pt2_stop
pt2_strand
pt3_contig
pt3_start
pt3_stop  
pt3_strand
"""
fieldnames = fieldnames.strip().split("\n")

myconnection = MySQLdb.connect(host = "localhost", user = 'root', passwd = "mock", db="pt3_annot")
mycursor = myconnection.cursor()

infilename = "/home/oaklander114/winshare/mysql_pt3/pt3_annot_ids_reduced.csv"
infile =  open(infilename, 'r')
linenumber = 0 

for line in infile:
    if linenumber > 0:
    line =  line.strip("\n\r")
    fields = line.split(',')
    print 'INSERT INTO ids SET '
    for i, fieldname in enumerate(fieldnames):
        query = []
        if i < 18:
            SQL1 = """
             %s = '%s',
             """ % (fieldname, fields[i])
            query.append(SQL1)
        else:
            SQL2 = """
             %s = '%s';
             """ % (FieldName, Fields[i])
            query.append(SQL2)
        SQL3 = " ".join(query)
        print SQL3
        mycursor.execute(SQL3)

    linenumber += 1
infile.close()
mycursor.close()
myconnection.commit()
myconnection.close()

这是错误信息:

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 'Org_rowNr_countsheet = '10578',' at line 1")

我认为在错误点显示语法的打印输出会很有用,因为脚本似乎正在生成它(在我看来是正确的):

INSERT INTO ids SET
  Org_rowNr_countsheet = '10579',
  Orig_row_10604 = '',
  pt3 = '300002',

等...但错误与第一行有关。这是更详细的错误报告:

%run /home/oaklander114/winshare/mysql_pt3/insert_rows_ids.py
INSERT INTO ids SET
Org_rowNr_countsheet='10578',
---------------------------------------------------------------------------
ProgrammingError                          Traceback (most recent call last)
/home/oaklander114/Canopy/appdata/canopy-1.4.1.1975.rh5-x86_64/lib/python2.7/site-   packages/IPython/utils/py3compat.pyc in execfile(fname, *where)
202             else:
203                 filename = fname
--> 204             __builtin__.execfile(filename, *where)

/home/oaklander114/winshare/mysql_pt3/insert_rows_ids.py in <module>()
 52             SQL3 = " ".join(query)
 53             print SQL3
---> 54             MyCursor.execute(SQL3)
 55 
 56     LineNumber += 1

/home/oaklander114/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/MySQL_python-1.2.5-    py2.7-linux-x86_64.egg/MySQLdb/cursors.pyc in execute(self, query, args)
203             del tb
204             self.messages.append((exc, value))
--> 205             self.errorhandler(self, exc, value)
206         self._executed = query
207         if not self._defer_warnings: self._warning_check()

/home/oaklander114/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/MySQL_python-1.2.5-py2.7-linux-x86_64.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 'Org_rowNr_countsheet='10578',' at line 1") 

这些是ids 表的列:

mysql>  SHOW COLUMNS FROM ids;
+----------------------+--------------+------+-----+---------+-------+
| Field                | Type         | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| Org_rowNr_countsheet | varchar(255) | NO   | PRI | NULL    |       |
| Org_row_10604        | varchar(255) | YES  |     | NULL    |       |
| pt3                  | varchar(255) | YES  |     | NULL    |       |
| pt3_ensembl_id       | varchar(255) | YES  |     | NULL    |       |
| status               | varchar(255) | YES  |     | NULL    |       |
| pt2_meth             | varchar(255) | YES  |     | NULL    |       |
| pt3_meth             | varchar(255) | YES  |     | NULL    |       |
| pt2_kegg_id          | varchar(255) | YES  |     | NULL    |       |
| pt2_uniprotID        | varchar(255) | YES  |     | NULL    |       |
| pt3_kegg_hit         | varchar(255) | YES  |     | NULL    |       |
| pt3_uniprot          | varchar(255) | YES  |     | NULL    |       |
| pt2_contig           | varchar(255) | YES  |     | NULL    |       |
| pt2_start            | varchar(255) | YES  |     | NULL    |       |
| pt2_stop             | varchar(255) | YES  |     | NULL    |       |
| pt2_strand           | varchar(255) | YES  |     | NULL    |       |
| pt3_contig           | varchar(255) | YES  |     | NULL    |       |
| pt3_start            | varchar(255) | YES  |     | NULL    |       |
| pt3_stop             | varchar(255) | YES  |     | NULL    |       |
| pt3_strand           | varchar(255) | YES  |     | NULL    |       |
+----------------------+--------------+------+-----+---------+-------+
19 rows in set (0.00 sec)

【问题讨论】:

    标签: python mysql sql mysql-python


    【解决方案1】:

    您的代码存在许多问题,包括功能和风格。对于风格问题,我建议您阅读PEP 8 -- Style Guide for Python Code。具体来说,为包、模块和类保留 CamelCase 将导致在 * 上突出显示更合适的语法。

    您在 cmets 中说您在 FieldNames 字符串中发现了拼写错误,但 INSERT 语句仍然静默失败,直到您切换到 VALUES 语法。我没有看到 INSERTSET 经常使用的语法变化,但它是正确的,并且可以使用 MySQL-Python:

    >>> curs.execute('create temporary table tbl (col1 varchar(10), col2 varchar(10))')
    0L
    >>> statement = r"""
    ... INSERT INTO tbl SET
    ...   col1 = "value1",
    ...   col2 = "value2";
    ... """
    >>> curs.execute(statement)
    1L
    >>> curs.execute("select * from tbl")
    1L
    >>> curs.fetchall()
    (('value1', 'value2'),)
    

    所以问题出在其他地方,无论是在您的代码中还是在您的期望中。除非你清楚地描述这个新问题(而且很可能会涉及重写你的大部分问题),否则我不能确切地说出了什么问题。但是,我可以指出您的方法存在的一些问题;解决这些问题可能会引导您找到解决方案。

    当你应该写 parameterized queries 时,你会浪费大量的空间来从一堆乱七八糟的字符串构建查询。忘记从字符串到列表的所有内容,并弄清楚何时需要逗号或分号;只需使用%s 作为每个值的占位符编写查询,并将这些值作为execute 方法as shown in the User's Guide 的第二个参数提供。

    自己解析 csv 文件而不是简单地使用 a standard library module for parsing csv files 也是一种浪费,如果您将 familiarize yourself with the with statement 用于文件对象(除其他外),您将编写更好的代码。这是一种不太容易出错的方法来做你想做的事情:

    import csv
    import MySQLdb 
    
    INSERT_STATEMENT = """
      INSERT INTO ids
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
                %s, %s, %s, %s, %s, %s, %s, %s, %s);
    """
    
    INPUT_PATH = '/home/oaklander114/winshare/mysql_pt3/pt3_annot_ids_reduced.csv'
    
    connection = MySQLdb.connect(host='localhost', user='root', passwd='mock',
                                 db='pt3_annot')
    
    with open(INPUT_PATH, 'r') as input_file, connection as cursor:
        reader = csv.reader(input_file)
        next(reader, None)  # skip the header row
        for row in reader:
            cursor.execute(INSERT_STATEMENT, row)
    
    connection.close()
    

    功能说明:

    • with 关键字和csv 模块是学习 Python 的必备工具。解析 csv 文件是您在求职面试中被要求演示的基本任务,在这种情况下,您将无法花时间编写一百行代码。
    • 确保在使用代码之前了解代码,如果遇到问题,请同时使用确实了解的代码。例如,next(reader, None)知道有标题行;通过阅读您的代码,我做到了。如果你在一个没有标题的文件中使用这个确切的代码,它会是错误的。
    • 以这种方式创建 MySQLdb 游标,使用 with 关键字,在 with 块的末尾自动提交事务。如果您想进行单独的交易,请在单独的 with 块中进行。
    • 另一方面,此代码中的游标对象在程序结束之前不会关闭——但考虑到 MySQLdb 实现游标的方式,这并不是真正的问题。如果您想了解更多信息,我对When to close cursors using MySQLdb 的回答会深入探讨该主题。
    • 您可以将INSERT_STATEMENT 的列名显式列出为idsVALUES 之间的元组。我将它们排除在外以节省答案中的空间,但这确实使列的顺序隐含在 SQL 语句和输入文件中。如果您想重用此代码,明确列列表可能会更安全。

    风格说明:

    • 以这种方式将 SQL 语句与三引号分隔符分开可以更容易地从视觉上区分您的 Python 代码。如果您想在 SQL 客户端应用程序之间复制和粘贴以进行测试,它还可以更轻松地选择语句。
    • 在我做的地方拆分值列表可以稍微更容易地计算占位符的数量 - 您只需手动计算第一行 10 即可看到总共有 19 个。
    • 以一种明确标识占位符数量而无需手动计算占位符数量的方式构建 MySQL 语句可能更具可读性和可维护性(例如,'INSERT INTO ids VALUES ({});'.format(','.join(['%s'] * 19))。请注意,这种方法仍然依赖光标的 execute 方法来正确处理要插入的值,这非常重要。
    • 此示例并未遵循 PEP 8 中的所有准则,主要是为了缩短长度,但它遵循了大部分准则(您也应该如此)。

    【讨论】:

      【解决方案2】:

      2 件事。我会从你的循环中取出 if 块,并确保预先添加正确的 SQL。

      SQL3 = 'UPDATE table SET ' + " ".join(query) + ';'  #don't forget WHERE clause as well...
      

      或者如果您要插入...您的有效 INSERT 语句

      您是否在文件中遇到空行?可以试试……

      而不是这个(在您的问题中格式不正确,仅供参考)

      for line in InFile:
          if LineNumber > 0:
          line =  line.strip("\n\r")
          #print line
          Fields = line.split(',')
      

      试试这个:

      for line in InFile:
          line =  line.strip("\n\r")
          if LineNumber > 0 and line != '':
              #print line
              Fields = line.split(',')
              #....rest of your code...
      

      【讨论】:

      • 谢谢。好主意将 SQL 语句放在连接之前。抱歉,我不明白如何将 if 块从 for 循环中取出?毕竟,当我评论(#)时,打印语句输出下方的行对我来说看起来也是有效的语法......还有更多线索吗? MyCursor.execute(SQL3)
      • 我尝试通过将 print SQL3 语句的输出复制到我的 MySQL 终端中来使用它。这个向我抛出另一个错误:mysql&gt; INSERT INTO ids SET Orig_row_10604='283'; ERROR 1054 (42S22): Unknown column 'Orig_row_10604' in 'field list'
      • Orig_row_10604 是您表中的一列吗?
      • 是的。我尝试使用 VALUES 而不是 SET 并没有解决问题,因为它仍然会引发语法错误(ERROR 1064 (42000))。
      • 越来越奇怪了 :( --> 我确实在列名中发现了一个拼写错误。从脚本中手动添加打印输出的前几行现在没有问题。所以虽然 python抛出语法错误,mysql没有它。它是否与Python如何访问数据库和执行代码有什么关系(例如,如果发现 --local-infile=1 必须添加到登录字符串能够使用'LOAD DATA LOCAL INFILE')...