使用Transpose和Pandas将XLSX导入SQLAlchemy数据库遇错求助
咱们一步步来拆解你遇到的这两个问题,逐个解决:
问题1:BLOB/TEXT column 'index' used in key specification without a key length
为什么会报错?
你转置DataFrame后,原来的列名变成了新DataFrame的index。而pandas的to_sql默认会把这个index作为数据库表的一列,并且自动尝试给它加主键约束。但MySQL有个规则:如果列类型是TEXT/BLOB(你的index内容大概率是长文本),创建主键或索引时必须指定长度,否则就会抛出这个1170错误。
两种解决方案
方案一:不导入DataFrame的index(推荐)
如果你不需要把这个index存到数据库里,直接在to_sql里加index=False参数就行,这样就不会把index作为列导入:dft.to_sql(file_basename.lower(), con=engine, if_exists='replace', index=False)方案二:保留index并指定列长度
要是你必须保留这个index作为表的一部分,可以先把它转成普通列,再指定它的SQL类型和长度:# 把index转为普通列,命名为你需要的名字,比如original_col dft_with_col = dft.reset_index().rename(columns={'index': 'original_col'}) # 定义该列的SQL类型,指定长度 dtype_map = {'original_col': sqlalchemy.types.VARCHAR(255)} # 导入时指定dtype dft_with_col.to_sql(file_basename.lower(), con=engine, if_exists='replace', index=False, dtype=dtype_map)
问题2:ValueError: not enough values to unpack (expected 2, got 1)
错误根源
问题出在你拆分文件名的代码:file_basename, extension = file.split('.')。如果某个Excel文件名里有多个点(比如report.v2.xlsx),或者极端情况没有点,split('.')返回的元素数量就不是2,这时候强行解包成两个变量就会触发这个ValueError。
修复方案
用Python标准库的os.path.splitext来安全拆分文件名和扩展名,不管文件名里有多少个点都能正确处理:
for file in os.listdir('.'): # 安全拆分文件名和扩展名 file_basename, extension = os.path.splitext(file) # 注意扩展名带点,所以判断是'.xlsx' if extension == '.xlsx': # 循环内读取当前Excel文件(你原来的代码里raw_lte是循环外的固定文件,这里要改) current_df = pd.read_excel(os.path.join(mydir, file), sheet_name='raw_4G') # 导入数据库,同样建议加index=False避免不必要的问题 current_df.to_sql(file_basename.lower(), con=engine, if_exists='replace', index=False)
另外注意:你原来的代码里raw_lte是在循环外读取的单个文件,循环里却处理所有xlsx文件,这逻辑不对——应该在循环里读取每个对应的Excel文件,上面的代码已经修正了这个问题。
内容的提问来源于stack exchange,提问作者Mahmoud Al-Haroon

