OleDbConnection读Excel需匹配驱动版本与文件格式,正确设置连接字符串、表名格式、HDR属性;DataTable列名/类型须与目标库严格对齐,预处理空值、合并单元格及混杂数据,分页读取并配置SqlBulkCopy参数以保障大批量导入稳定。

用 OleDbConnection 读 Excel 文件时,连接字符串写错就直接报错
Excel 不是数据库,但 .NET 可以用 OLE DB 当“伪数据库”读——前提是连接字符串对。常见错误是版本没匹配:Provider=Microsoft.ACE.OLEDB.12.0 对应 Excel 2007+(.xlsx),而 Provider=Microsoft.Jet.OLEDB.4.0 只支持 .xls,且不兼容 64 位进程。
- 64 位程序必须装 Microsoft Access Database Engine 2016 Redistributable(64 位),装 32 位驱动会抛
System.Data.OleDb.OleDbException: '未在本地计算机上注册 OLE DB 提供程序' -
Extended Properties="Excel 12.0;HDR=YES;"中的HDR=YES表示首行是列名;如果 Excel 没标题行,得改成HDR=NO,否则数据会错位 - 表名不是文件名,而是类似
[Sheet1$]或[数据表$A1:D100],带中括号和美元符,漏掉或写成Sheet1就报“找不到可用来处理此命令的表”
用 SqlBulkCopy 导入前,DataTable 列名和数据库字段必须严格对齐
很多人以为只要列数一样就能 bulk copy,其实 SqlBulkCopy 默认按列**顺序**映射,不是按名字。一旦 Excel 表头顺序和目标表字段顺序不一致,数据就全塞错字段。
- 显式调用
ColumnMappings.Add("ExcelColumnName", "DbColumnName"),哪怕名字相同也建议加——避免因 Excel 多列、空列、隐藏列导致错位 -
DataTable的列类型要尽量贴近数据库类型:比如 Excel 里“2023-01-01”可能被 OLE DB 自动识别为DateTime,但若单元格混了文本“N/A”,整列就变成string,bulk copy 时会报无法将 String 类型转换为 DateTime - 目标 SQL 表最好关掉约束和触发器:
SqlBulkCopy.SqlRowsCopied += ...可监控进度,但别在导入中途查表——SqlBulkCopy是单批次提交,查不到中间状态
遇到日期/数字格式混乱,别靠 Excel 手动调整,用 DataTable 预处理
Excel 单元格格式只是显示层,底层值可能是文本、浮点数、OLE 自定义日期序列。直接读进 DataTable 后,同一列经常出现 DateTime、double、string 混杂,SqlBulkCopy 一碰就崩。
- 读完后遍历
DataRow,对疑似日期列用DateTime.TryParse统一转;对数字列用double.TryParse+Convert.ToDecimal转目标精度 - 空值别留
""或"NULL"字符串,统一设为DBNull.Value,否则数据库非空字段会拒绝插入 - 如果 Excel 有合并单元格,OLE DB 会把合并区域第一格值读出来,其余为空——这不是 bug,是设计如此;得提前用 EPPlus 或 ClosedXML 解析结构,
OleDbConnection压根不识别合并
批量导入大文件(>10MB)时,内存和事务控制比代码简洁更重要
一次性读整个 Excel 到 DataTable 再 bulk copy,10 万行以上就容易爆内存,尤其 Excel 本身含样式、公式、图片等冗余信息。
- 用
OleDbCommand分页查:比如SELECT * FROM [Sheet1$] WHERE F1 IS NOT NULL加条件过滤空行,减少加载量 -
SqlBulkCopy.BatchSize = 10000,别用默认值(0 = 全部当一批),避免超时或日志暴涨;同时设SqlBulkCopy.EnableStreaming = true(.NET 4.5+),让数据流式传输,不全载入内存 - 别在
SqlBulkCopy.WriteToServer()外包TransactionScope——它默认隔离级别太高,长事务锁表严重;改用显式SqlTransaction并设IsolationLevel.ReadCommitted
真正麻烦的从来不是“怎么连上 Excel”,而是 Excel 数据本身不规范、类型不一致、边界情况多。工具链越简单(OleDb → DataTable → SqlBulkCopy),越要花时间在预处理和错误兜底上——而不是指望某段“万能导入代码”自动搞定一切。


















