通过python把csv表格导入mysql数据库
·
修改数据库参数、CSV文件位置、表名称即可在mysql数据库导入CSV文件,亲测数百万条数据导入可用。需要注意CSV文件编码必须是UTF-8,可以用记事本另存修改。
此代码使用了批量插入,每次插入1000条数据,避免数据量过大导致无法执行。
以下是源代码:
import pandas as pd
import mysql.connector
from mysql.connector import Error
import os
import time
import numpy as np
def import_csv_to_mysql(csv_file, table_name, db_config):
"""
将CSV文件导入到MySQL数据库
参数:
csv_file: CSV文件路径
table_name: 数据库表名
db_config: 数据库连接配置字典
"""
try:
# 读取CSV文件 - 将所有列都设为字符串类型以避免混合类型警告
print("开始读取CSV文件...")
# 方法1:先读取前几行获取列数,然后为所有列指定字符串类型
df_sample = pd.read_csv(csv_file, nrows=5)
total_columns = len(df_sample.columns)
# 创建所有列的dtype映射,全部设为字符串类型
dtype_dict = {i: str for i in range(total_columns)}
# 重新读取整个文件,所有列都设为字符串类型
df = pd.read_csv(csv_file, dtype=dtype_dict, keep_default_na=False, na_values=[''])
print(f"成功读取CSV文件,共{len(df)}行数据,{len(df.columns)}列")
# 显示数据列信息
print(f"CSV文件列名: {list(df.columns)}")
print("各列数据类型:")
for i, col in enumerate(df.columns):
print(f" 第{i}列 '{col}': {df.dtypes.iloc[i]}")
# 连接MySQL数据库 - 增加超时设置
db_config_with_timeout = db_config.copy()
db_config_with_timeout.update({
'connect_timeout': 300,
'pool_size': 10
})
connection = mysql.connector.connect(**db_config_with_timeout)
# 设置会话超时时间
cursor = connection.cursor()
cursor.execute("SET SESSION wait_timeout = 28800") # 8小时
cursor.execute("SET SESSION interactive_timeout = 28800") # 8小时
cursor.execute("SET GLOBAL max_allowed_packet=1073741824") # 1GB
# 检查表是否存在
cursor.execute(f"SHOW TABLES LIKE '{table_name}'")
table_exists = cursor.fetchone() is not None
if table_exists:
print(f"表 '{table_name}' 已存在,将追加数据")
# 获取现有表的列信息
cursor.execute(f"DESCRIBE {table_name}")
existing_columns = [column[0] for column in cursor.fetchall()]
print(f"现有表的列: {existing_columns}")
# 检查是否有新列需要添加
new_columns = set(df.columns) - set(existing_columns)
if new_columns:
print(f"发现新列需要添加: {new_columns}")
for column in new_columns:
# 所有新列都设为VARCHAR(255)类型
alter_query = f"ALTER TABLE {table_name} ADD COLUMN `{column}` VARCHAR(255)"
cursor.execute(alter_query)
print(f"已添加列: {column}")
else:
# 创建新表 - 所有列都设为VARCHAR类型
print(f"表 '{table_name}' 不存在,将创建新表")
# 构建CREATE TABLE语句
columns_def = []
for i, column in enumerate(df.columns):
# 所有列都设为VARCHAR类型,避免任何类型转换问题
# 可以根据需要调整长度
if len(column) > 50 or any(keyword in column.lower() for keyword in ['content', 'business_scope', 'description', 'remark', '备注', '描述']):
column_type = 'VARCHAR(1000)'
else:
column_type = 'VARCHAR(120)'
columns_def.append(f"`{column}` {column_type}")
create_table_query = f"""
CREATE TABLE {table_name} (
myid INT AUTO_INCREMENT PRIMARY KEY,
{', '.join(columns_def)}
)
"""
cursor.execute(create_table_query)
print(f"已创建新表: {table_name}")
# 插入数据 - 分批插入避免超时
print("开始插入数据...")
# 构建INSERT语句
placeholders = ', '.join(['%s'] * len(df.columns))
columns = ', '.join([f"`{col}`" for col in df.columns])
insert_query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
# 分批插入数据
batch_size = 1000 # 每批插入1000行
total_rows = len(df)
inserted_rows = 0
for i in range(0, total_rows, batch_size):
end_idx = min(i + batch_size, total_rows)
batch_df = df.iloc[i:end_idx]
# 将NaN值替换为None(SQL NULL)
batch_data = []
for row in batch_df.itertuples(index=False):
processed_row = []
for value in row:
if pd.isna(value) or value == 'nan' or value == 'NaN' or value == '' or value == 'None' or value == 'NULL':
processed_row.append(None)
else:
# 确保所有值都是字符串,避免类型问题
processed_row.append(str(value) if value is not None else None)
batch_data.append(tuple(processed_row))
try:
cursor.executemany(insert_query, batch_data)
connection.commit()
inserted_rows += len(batch_data)
print(f"已插入 {inserted_rows}/{total_rows} 行数据 ({inserted_rows/total_rows*100:.2f}%)")
# 每插入10000行休息一下,避免服务器压力过大
if inserted_rows % 10000 == 0:
time.sleep(1)
except Error as e:
print(f"插入批次 {i}-{end_idx} 时出错: {e}")
print(f"问题数据样本: {batch_data[0] if batch_data else '无数据'}")
connection.rollback()
# 尝试逐行插入以找到具体错误行
print("尝试逐行插入以定位错误...")
success_count = 0
for j, row_data in enumerate(batch_data):
try:
cursor.execute(insert_query, row_data)
success_count += 1
except Error as e:
print(f"第 {i+j} 行插入失败: {e}")
print(f"失败行数据: {row_data}")
# 跳过错误行继续
continue
connection.commit()
inserted_rows += success_count
print(f"本批次成功插入 {success_count} 行,跳过 {len(batch_data) - success_count} 行")
print(f"成功插入 {inserted_rows} 行数据到表 '{table_name}'")
except Error as e:
print(f"数据库错误: {e}")
except Exception as e:
print(f"错误: {e}")
finally:
if 'connection' in locals() and connection.is_connected():
cursor.close()
connection.close()
print("数据库连接已关闭")
# 配置信息 - 在这里修改你的配置
def get_config():
"""返回配置信息,方便修改"""
return {
'csv_file': 'd:\\import\\test2.csv', # 你的CSV文件路径
'table_name': 'stu_table', # 数据库表名
'db_config': {
'host': 'localhost',
'database': 'jing', # 你的数据库名
'user': 'root', # 你的用户名
'password': 'password', # 你的密码
'charset': 'utf8mb4',
'connect_timeout': 300
}
}
if __name__ == "__main__":
# 获取配置
config = get_config()
# 检查CSV文件是否存在
if not os.path.exists(config['csv_file']):
print(f"错误: CSV文件 '{config['csv_file']}' 不存在")
print("请确保:")
print("1. CSV文件存在于当前目录")
print("2. 在get_config()函数中正确设置了csv_file路径")
print("3. CSV文件包含列标题")
else:
# 执行导入
print(f"开始导入 {config['csv_file']} 到MySQL数据库...")
start_time = time.time()
import_csv_to_mysql(
csv_file=config['csv_file'],
table_name=config['table_name'],
db_config=config['db_config']
)
end_time = time.time()
print(f"导入完成,总耗时: {end_time - start_time:.2f} 秒")
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)