_mysql_exceptions 错误(1064,“检查与您的 MySQL 服务器版本相对应的手册,以获取在 'default 附近使用的正确语法)值
Posted
技术标签:
【中文标题】_mysql_exceptions 错误(1064,“检查与您的 MySQL 服务器版本相对应的手册,以获取在 \'default 附近使用的正确语法)值【英文标题】:_mysql_exceptions error(1064, "check the manual that corresponds to your MySQL server version for the right syntax to use near 'default) VALUES_mysql_exceptions 错误(1064,“检查与您的 MySQL 服务器版本相对应的手册,以获取在 'default 附近使用的正确语法)值 【发布时间】:2018-05-05 10:06:42 【问题描述】:我正在尝试使用 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 服务器版本相对应的手册,了解在 'default 附近使用的正确语法) VALUES ('5', '0', '0', 'integer', '', '', '1', '', 'Base Parameters', '' at line 1")
下面是我尝试导入的 csv 的屏幕截图:
如您所见,它无法读取“基本参数”之后的数字“1”并引发错误。有人可以帮我解决问题吗?
【问题讨论】:
DEFAULT
是 MySQL 中的保留字。如果您使用保留字命名列,则每次引用列名时都必须用反引号将其分隔。
@BillKarwin,你是对的,但这不能解释为什么它没有从 ROWNUM
读取“1”
【参考方案1】:
_mysql_exceptions.ProgrammingError: (1064, "您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册以了解在 'default 附近使用的正确语法) VALUES ('5', '0', '0', 'integer', '', '', '1', '', 'Base Parameters', '' at line 1")
您看到的是 INSERT 语句的片段。它没有向您显示整个 INSERT 语句,而是将其切断。您说您认为它没有读取输入数据的 ROWNUM 字段中的“1”,但您误解了错误消息。
您在错误消息中看到两个相邻的单引号只是一个巧合。错误信息的格式如下:
_mysql_exceptions.ProgrammingError: (1064, "您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以了解在第 1 行的 '...' 附近使用的正确语法")
...
将是长 SQL 语句的片段,从混淆解析器的第一个标记开始,在这种情况下持续 80 个字符。这个 80 个字符的片段是:
default) VALUES ('5', '0', '0', 'integer', '', '', '1', '', 'Base Parameters', '
第80个字符是单引号纯属偶然,然后报错信息中的下一个字符也是单引号。它不是一个空字符串来代替您希望从输入中读取的值 '1'
。事实上,我假设它正在从输入中读取数据值。
所以错误中报告的问题是您使用SQL reserved word DEFAULT
作为列名。这个 Python 脚本没有对它进行定界。因此,INSERT 语句中保留字的出现会使解析器感到困惑。
我相信您可以在 Python 脚本中通过格式化 INSERT 语句中反引号内的列名来解决此问题:
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)
您也可以编辑输入的 CSV 文件以避免在标题中定义的列名中使用 SQL 保留字。
【讨论】:
感谢@BillKarwin 的精彩回答。这实际上解决了问题并挽救了我的一天,我很高兴我今天学到了一些新东西。 如果我在 INSERT 语句中使用反引号,我能够成功地将数据加载到 mysql 数据库中。但是,如果我尝试通过 Django 管理页面查看同一个表,则会为同一个表抛出 "string index out of range" 错误。是因为 len(header) 语句吗? 通常会有一条错误消息告诉您发生错误的行号。您应该查看代码中的那一行。 我无法找到错误的位置,因为 Django 没有显示。以下是错误的屏幕截图。【参考方案2】:@BillKarwin,当我使用 Django 管理页面查看加载到 mysql db 中的同一个表时(修改为将 DEFAULT
作为字段名之后),它抛出了 " 字符串索引范围” 错误。我无法确定引发错误的确切位置。是因为main
函数中的len(header)
代码吗?
【讨论】:
以上是关于_mysql_exceptions 错误(1064,“检查与您的 MySQL 服务器版本相对应的手册,以获取在 'default 附近使用的正确语法)值的主要内容,如果未能解决你的问题,请参考以下文章
_mysql_exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query')(示
sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (2059, "Authentication pl