使用VB.NET将Excel导入SQL Server时日期转换失败问题求助
问题根因
- 日期转换逻辑依赖系统区域设置:
Convert.ToDateTime()和ToShortDateString()方法的输出格式受运行设备的系统区域配置影响,比如部分区域默认输出MM/dd/yyyy格式的日期,和SQL Server期望的格式不匹配就会触发转换失败。 - OLEDB读取Excel列类型判断异常:默认情况下OLEDB驱动会根据Excel前8行数据自动判断列的数据类型,如果你修改数据后某行日期的单元格格式和前8行不一致,驱动可能会将该单元格读取为乱码文本或DBNull,转换时直接报错。
- SQL字符串拼接风险:直接拼接日期字符串到SQL语句中,没有统一的日期格式约束,不同环境下极易出现格式兼容问题,同时还存在SQL注入漏洞。
修复方案
1. 调整Excel连接字符串
在Excel的OLEDB连接字符串中加入IMEX=1参数,强制驱动将所有列按文本格式读取,避免自动类型判断导致的读取异常,参考连接字符串:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=你的Excel文件路径;Extended Properties="Excel 12.0 Xml;HDR=YES;IMEX=1";
2. 替换日期转换逻辑
使用DateTime.TryParseExact方法指定固定的yyyy-MM-dd格式进行日期转换,避免系统区域影响,同时增加空值/格式异常判断,可提前定位出错行。
3. 改用参数化查询执行插入
替换字符串拼接SQL的方式,通过参数传递日期和其他字段值,彻底解决日期格式兼容问题。
修改后的参考代码
Try OLEcon.Open() With OLEcmd .Connection = OLEcon .CommandText = "select * from [Sheet1$]" End With OLEda.SelectCommand = OLEcmd OLEda.Fill(OLEdt) ' 提前定义参数化SQL,不需要拼接变量 Dim insertSql As String = "INSERT INTO MasterStaffListTry (EENo,Name,Age,AgeCategory,Gender,Ethnicity,Grade,Category,Department,Position,ReportingTo,LastEmploymentDate,DateJoin,LOCUM,Status) VALUES (@EENo,@Name,@Age,@AgeCategory,@Gender,@Ethnicity,@Grade,@Category,@Department,@Position,@ReportingTo,@LastEmploymentDate,@DateJoin,@LOCUM,@Status)" For Each r As DataRow In OLEdt.Rows ' 年龄转换增加异常判断 Dim intAge As Integer If Not Integer.TryParse(r(2)?.ToString(), intAge) Then ' 可在此处加日志记录该行年龄格式错误,跳过该行继续执行 Continue For End If ' 日期转换指定固定格式,不受系统区域影响 Dim dateLED As Date Dim ledStr = r(11)?.ToString().Trim() If Not DateTime.TryParseExact(ledStr, "yyyy-MM-dd", Globalization.CultureInfo.InvariantCulture, Globalization.DateTimeStyles.None, dateLED) Then ' 可在此处加日志记录该行LastEmploymentDate格式错误,跳过该行继续执行 Continue For End If Dim dateDJ As Date Dim djStr = r(12)?.ToString().Trim() If Not DateTime.TryParseExact(djStr, "yyyy-MM-dd", Globalization.CultureInfo.InvariantCulture, Globalization.DateTimeStyles.None, dateDJ) Then ' 可在此处加日志记录该行DateJoin格式错误,跳过该行继续执行 Continue For End If ' 调用参数化方法执行插入,需对应修改saveData方法支持传入参数数组 Dim params As New List(Of SqlParameter) From { New SqlParameter("@EENo", If(r(0)?.ToString(), DBNull.Value)), New SqlParameter("@Name", If(r(1)?.ToString(), DBNull.Value)), New SqlParameter("@Age", intAge), New SqlParameter("@AgeCategory", If(r(3)?.ToString(), DBNull.Value)), New SqlParameter("@Gender", If(r(4)?.ToString(), DBNull.Value)), New SqlParameter("@Ethnicity", If(r(5)?.ToString(), DBNull.Value)), New SqlParameter("@Grade", If(r(6)?.ToString(), DBNull.Value)), New SqlParameter("@Category", If(r(7)?.ToString(), DBNull.Value)), New SqlParameter("@Department", If(r(8)?.ToString(), DBNull.Value)), New SqlParameter("@Position", If(r(9)?.ToString(), DBNull.Value)), New SqlParameter("@ReportingTo", If(r(10)?.ToString(), DBNull.Value)), New SqlParameter("@LastEmploymentDate", dateLED), New SqlParameter("@DateJoin", dateDJ), New SqlParameter("@LOCUM", If(r(13)?.ToString(), DBNull.Value)), New SqlParameter("@Status", If(r(14)?.ToString(), DBNull.Value)) } resul = saveData(insertSql, params) If resul Then Timer1.Start() End If Next Catch ex As Exception ' 全局异常捕获记录错误日志 Finally OLEcon.Close() End Try
内容的提问来源于stack exchange,提问作者lowkey
相关产品推荐
相关产品推荐

