Pandas写入MSSQL时触发无对应列属性AttributeError报错
问题场景
尝试将Excel文件导入部署在Docker中的MSSQL实例,运行Python脚本时触发Pandas相关属性报错,暂未定位根因。
问题代码
import pandas as pd import pyodbc # 读取Excel文件 data = pd.read_excel (r"C:\Users\c.stembridge\OneDrive - NEWREST GROUP SERVICES\Overtime Forecast Report.xlsx", sheet_name='Daily Hrs2') df = pd.DataFrame(data) # 连接SQL Server conn = pyodbc.connect("DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost;UID=SA;PWD=Working@2022;DATABASE=testdb;Encrypt=no;TrustServerCertificate=yes") cursor = conn.cursor() # 建表 cursor.execute(''' CREATE TABLE Overtime_Forecast ( date nvarchar(10) primary key, day nvarchar(9), hrs int, dl int, catered int, hrs_diff_btwn_last_day int, catered_flight_diff int, employees_OT_count int, carriers int, whole int, half int, total_carts int ) ''') # 循环插入DataFrame数据 for row in df.itertuples(): cursor.execute(''' INSERT INTO Overtime_Forecast ( date nvarchar(10) primary key, day nvarchar(9), hrs int, dl int, catered int, hrs_diff_btwn_last_day int, catered_flight_diff int, employees_OT_count int, carriers int, whole int, half int, total_carts int) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) ''', row.Date, row.Day, row.Hrs, row.DL, row.Catered, row.Hrs_diff_btwn_last_day, row.Catered_flight_diff, row.Employees_OT_count, row.Carriers, row.Whole, row.Half, row.Total_carts ) conn.commit()
报错信息
row.Hrs_diff_btwn_last_day, AttributeError: 'Pandas' object has no attribute 'Hrs_diff_btwn_last_day'
已确认信息
- Excel中对应列头名称确实为
Hrs_diff_btwn_last_day - Excel全部列名依次为:Date, Day, Hrs, DL, Catered, Hrs_diff_btwn_last_day, Catered_flight_diff, Employees_OT_count, Carriers, Whole, Half, Total_carts
根因与修复方案
核心报错原因:列名存在隐藏不可见字符
肉眼核对列名一致不代表pandas读取到的列名完全匹配,大概率是该列名前后存在空格、零宽空格等不可见字符,导致itertuples()生成的命名元组没有对应名称的属性。
先运行以下代码打印真实列名:print([repr(col) for col in df.columns])如果输出中
Hrs_diff_btwn_last_day带多余空格/特殊字符,先统一清洗列名:# 去除所有列名前后的空白字符 df.columns = df.columns.str.strip()代码存在两处额外问题,修复列名后也会触发报错:
itertuples()点取值方式兼容性差:列名只要存在不符合Python标识符规则的字符就会访问失败,可改用位置索引取值,或直接使用pandas原生to_sql方法替代循环插入,效率更高也不会出现属性访问问题。- INSERT语句语法错误:INSERT的字段列表只需要填字段名,不需要加
nvarchar(10)、primary key这类建表时用的类型/约束定义,否则会报SQL语法错误。
修正后可运行的核心代码片段
# 先清洗列名 df.columns = df.columns.str.strip() # 插入语句修正:只保留字段名 insert_sql = ''' INSERT INTO Overtime_Forecast ( date, day, hrs, dl, catered, hrs_diff_btwn_last_day, catered_flight_diff, employees_OT_count, carriers, whole, half, total_carts ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?) ''' # 改用位置索引取值,避免属性访问问题;itertuples默认第一列是Index,业务字段从索引1开始取 for row in df.itertuples(): cursor.execute(insert_sql, row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12] ) conn.commit()
更推荐直接用
df.to_sql('Overtime_Forecast', conn, if_exists='append', index=False)替代手写循环插入,代码更简洁性能也更好。
内容的提问来源于stack exchange,提问作者user18495643
相关产品推荐
相关产品推荐

