使用SQLAlchemy将CSV文件导入PostgreSQL时遭遇非预期的double precision类型错误
问题诊断与解决方案
从你的错误信息和描述来看,这个问题的根源大概率是CSV文件列错位或者pandas自动类型推断不一致导致的,下面一步步分析并给出解决办法:
1. 优先排查CSV文件的格式问题
错误提示里提到invalid input syntax for type double precision: "30.580*",而这个带*的值本应存入text类型的sec_thr列,但实际上它被传到了decimal类型的数值列中。这种情况通常意味着:
- 第二个CSV文件的第4行存在格式错误:比如遗漏了逗号、或者有包含逗号的未转义文本,导致列整体错位,把
sec_thr列的带*值挤到了后面的数值类型列里。 - 两个CSV文件的表头顺序不一致:第一个文件的列顺序和表结构匹配,但第二个文件的列顺序变了,导致数据对应到错误的列。
排查步骤:
- 用文本编辑器打开第二个CSV文件,对比表头和
gp_times表的列顺序,确保完全一致。 - 查看第4行数据(注意区分表头行和数据行),数一下列的数量是否和表头一致,有没有明显的格式错误(比如某个字段里的逗号没被引号包裹)。
2. 强制指定列数据类型,避免pandas自动推断错误
即使CSV格式没问题,pandas的自动类型推断可能在不同文件间出现偏差:比如第一个CSV的sec_thr列全是带*的字符串,pandas推断为object(对应SQL的text);但第二个CSV里该列可能先出现了纯数字值,导致pandas推断为float类型,后续遇到带*的值时,虽然能存入DataFrame,但to_sql时会尝试把它作为数值插入,引发错误。
解决办法:在pd.read_csv时强制指定每一列的数据类型,和表结构严格对应:
# 定义和表结构匹配的dtype字典 csv_dtype = { 'index': str, 'month': str, 'day': str, 'yr': int, 'lge': str, 'rnd': int, 'session': str, 'trk': str, 'pos': str, 'rdr_num': int, 'f_name': str, 'l_name': str, 'nat': str, 'team': str, 'manu': str, 'num_of_laps': int, 'run_num': int, 'f_tire': str, 'r_tire': str, 'laps_on_f': int, 'laps_or_r': int, 'lap_num': int, 'lap_time': str, 'lap_seconds': float, 'lap_valid': bool, 'pit': bool, 'sec_one': str, 'one_seconds': float, 'one_valid': bool, 'sec_two': str, 'two_seconds': float, 'two_valid': bool, 'sec_thr': str, 'thr_seconds': float, 'thr_valid': bool, 'sec_four': str, 'four_seconds': float, 'four_valid': bool, 'avg_spd': str } # 在read_csv时指定dtype df = pd.read_csv(f, dtype=csv_dtype)
这样可以确保pandas不会错误推断列类型,所有文本列都被强制识别为字符串,避免插入时类型不匹配。
3. 额外的验证步骤
为了进一步确认问题,可以在循环里添加临时验证,提前发现异常:
for file in fLis: with open(file, "r", encoding="utf-8") as f: df = pd.read_csv(f, dtype=csv_dtype) print(file) # 检查df的列顺序和表结构是否一致 table_columns = [col.strip() for col in createTimesTable.split('(')[1].split(')')[0].split('\n')[1:-1]] table_columns = [col.split()[0] for col in table_columns] if list(df.columns) != table_columns: print(f"⚠️ 列顺序不匹配!文件{file}的列顺序:{list(df.columns)}") print(f"表结构列顺序:{table_columns}") continue # 检查sec_thr列是否有不符合格式的值 invalid_sec_thr = df[~df['sec_thr'].astype(str).str.match(r'^\d+\.\d+\*?$')] if not invalid_sec_thr.empty: print(f"⚠️ 文件{file}中sec_thr列存在异常值:{invalid_sec_thr['sec_thr'].tolist()}") # 执行插入 df.to_sql("gp_times", con = engine, if_exists = "append", index = False)
内容的提问来源于stack exchange,提问作者user12526523
相关产品推荐
相关产品推荐

