_mysql_exceptions错误(1064,“检查与您的MySQL服务器版本相对应的手册,在正确的语法附近使用默认值)VALUES

我想使用python脚本自动导入CSV到MySQL数据库。 我使用https://bitbucket.org/richardpenman/csv2mysql的脚本来完成这个任务。 以下是代码:

import os import re import sys import csv import time import argparse import collections import MySQLdb import warnings # suppress annoying mysql warnings warnings.filterwarnings(action='ignore', category=MySQLdb.Warning) def get_type(s): """Find type for this string """ # try integer type try: v = int(s) except ValueError: pass else: if abs(v) > 2147483647: return 'bigint' else: return 'int' # try float type try: float(s) except ValueError: pass else: return 'double' # check for timestamp dt_formats = ( ('%Y-%m-%d %H:%M:%S', 'datetime'), ('%Y-%m-%d %H:%M:%S.%f', 'datetime'), ('%Y-%m-%d', 'date'), ('%H:%M:%S', 'time'), ) for dt_format, dt_type in dt_formats: try: time.strptime(s, dt_format) except ValueError: pass else: return dt_type # doesn't match any other types so assume text if len(s) > 255: return 'text' else: return 'varchar(255)' def most_common(l, default='varchar(255)'): """Return most common value from list """ # some formats trump others if l: for dt_type in ('text', 'bigint'): if dt_type in l: return dt_type return max(l, key=l.count) return default def get_col_types(input_file, max_rows=1000): """Find the type for each CSV column """ csv_types = collections.defaultdict(list) print (os.getcwd()) # os.chdir("scripts/CSV") reader = csv.reader(open(input_file)) # test the first few rows for their data types for row_i, row in enumerate(reader): if row_i == 0: header = row else: for col_i, s in enumerate(row): data_type = get_type(s) csv_types[header[col_i]].append(data_type) if row_i == max_rows: break # take the most common data type for each row return [most_common(csv_types[col]) for col in header] def get_insert(table, header): """Generate the SQL for inserting rows """ field_names = ', '.join(header) field_markers = ', '.join('%s' for col in header) return 'INSERT INTO %s (%s) VALUES (%s);' % \ (table, field_names, field_markers) def format_header(row): """Format column names to remove illegal characters and duplicates """ safe_col = lambda s: re.sub('\W+', '_', s.lower()).strip('_') header = [] counts = collections.defaultdict(int) for col in row: col = safe_col(col) counts[col] += 1 if counts[col] > 1: col = '{}{}'.format(col, counts[col]) header.append(col) return header def main(input_file, user, password, host, table, database, max_inserts=10000): print ("Importing `%s' into MySQL database `%s.%s'" % (input_file, database, table)) db = MySQLdb.connect(host=host, user=user, passwd=password, charset='utf8') cursor = db.cursor() # create database and if doesn't exist cursor.execute('CREATE DATABASE IF NOT EXISTS %s;' % database) db.select_db(database) # define table print ("Analyzing column types ...") col_types = get_col_types(input_file) print (col_types) header = None for i, row in enumerate(csv.reader(open(input_file))): if header: while len(row) < len(header): row.append('') # this row is missing columns so pad blank values cursor.execute(insert_sql, row) if i % max_inserts == 0: db.commit() print ("commit") else: header = format_header(row) print ("Inserting rows ...") # SQL string for inserting data insert_sql = get_insert(table, header) # commit rows to database print ("Committing rows to database ...") db.commit() print ("Done!") if __name__ == '__main__': parser = argparse.ArgumentParser(description='Automatically insert CSV contents into MySQL') parser.add_argument('--table', dest='table', help='Set the name of the table. If not set the CSV filename will be used') parser.add_argument('--database', dest='database', default=os.environ['MYSQL_DATABASE'], help='Set the name of the database. If not set the test database will be used') parser.add_argument('--user', dest='user', default=os.environ['MYSQL_USER'], help='The MySQL login username') parser.add_argument('--password', dest='password', default=os.environ['MYSQL_PASSWORD'], help='The MySQL login password') parser.add_argument('--host', dest='host', default=os.environ['MYSQL_CONTAINER_NAME'], help='The MySQL host') parser.add_argument('input_file', help='The input CSV file') args = parser.parse_args(sys.argv[1:]) if not args.table: # use input file name for table args.table = os.path.splitext(os.path.basename(args.input_file))[0] main(args.input_file, args.user, args.password, args.host, args.table, args.database) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "WebApp.settings.local") from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) 

即使我能读取我的CSV文件和导入,它是抛出一个特定的表错误,即

 DROP TABLE IF EXISTS `param_system`; CREATE TABLE `param_system` ( `ID` int(11) NOT NULL, `EXTERNAL_EDIT` int(11) DEFAULT '0', `INTERNAL_EDIT` int(11) DEFAULT '0', `FORTRAN_TYPE` varchar(50) DEFAULT NULL, `LABEL` varchar(255) DEFAULT NULL, `DESCRIPTION` varchar(255) DEFAULT NULL, `HELP_ID` int(11) DEFAULT '0', `HELP_TEXT` text DEFAULT NULL, `GROUPNAME` varchar(255) DEFAULT NULL, `ROWNUM` int(11) DEFAULT '0', `WIDGET` varchar(50) DEFAULT NULL, `OPTIONS` varchar(255) DEFAULT NULL, `DISABLED` int(11) DEFAULT '0', `READONLY` int(11) DEFAULT '0', `REQUIRED` int(11) DEFAULT '0', `UI` text DEFAULT NULL, `MIN_VALUE` varchar(50) DEFAULT NULL, `MAX_VALUE` varchar(50) DEFAULT NULL, `FORM_VAR_NAME` varchar(255) DEFAULT NULL, `PARAM` varchar(255) DEFAULT NULL, `VAL` varchar(255) DEFAULT NULL, `DEFAULT` varchar(255) DEFAULT NULL ) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8; 

被抛出的错误是:

_mysql_exceptions.ProgrammingError:(1064,“你的SQL语法错误;查看对应于你的MySQL服务器版本的手册,在正确的语法附近使用默认值)VALUES('5','0','0' ,'整数','','','1','','基本参数',''在第1行“)

下面是我试图导入的csv的屏幕截图: param_system.csv

正如你所看到的,在“Base Parameters”之后不能读出数字“1”并抛出错误。 有人能帮我解决问题吗?

_mysql_exceptions.ProgrammingError:(1064,“你的SQL语法错误;查看对应于你的MySQL服务器版本的手册,在正确的语法附近使用默认值)VALUES('5','0','0' ,'整数','','','1','','基本参数',''在第1行“)

你所看到的是INSERT语句的一个片段。 它并没有向您显示整个INSERT语句,它会将其切断。 你说你认为它不是读取input数据的ROWNUM字段中的'1',而是错误地解释错误信息。

在错误信息中,您看到两个单引号彼此相邻,这只是一个巧合。 错误消息格式如下:

_mysql_exceptions.ProgrammingError:(1064,“你的SQL语法有错误;检查与你的MySQL服务器版本相对应的手册,在第一行的'…'附近使用正确的语法)

其中...将是长SQL语句的一个片段,从混淆parsing器的第一个令牌开始,并在此情况下继续保留80个字符。 这个80个字符的片段是:

 default) VALUES ('5', '0', '0', 'integer', '', '', '1', '', 'Base Parameters', ' 

错误消息中的下一个字符也是单引号,这纯粹是偶然的,第80个字符是单引号。 它不是一个空string,而不是您希望从input中读取的值'1' 。 实际上,我假设它正在从input中读取数据值。

因此,错误中报告的问题是您正在使用SQL保留字 DEFAULT作为列名。 这个Python脚本不会分隔它。 因此,INSERT语句中保留字的出现会使parsing器混淆。

我相信你可以通过在INSERT语句中的back-ticks内的格式化列名来解决这个问题。

 def get_insert(table, header): """Generate the SQL for inserting rows """ field_names = ', '.join('`%s`' % col for col in header) field_markers = ', '.join('%s' for col in header) return 'INSERT INTO %s (%s) VALUES (%s);' % \ (table, field_names, field_markers) 

您也可以编辑inputCSV文件,以避免在标题中定义的列名中使用SQL保留字。

@BillKarwin,当我使用Djangopipe理页面查看在MySQL数据库中加载的同一个表(在修改为将DEFAULT作为字段名称后),它抛出“string索引超出范围”错误。 我无法准确指出发生错误的确切位置。 是因为main函数中的len(header)代码? SS_1 SS_2