使用BulkCopy插入SQL表时数值不符问题求助
解决SqlBulkCopy插入decimal列时的数值精度问题
我之前碰到过一模一样的坑!这事儿本质是浮点数精度误差在搞鬼,根源是你的DataTable列类型和SQL表的decimal(15,4)不匹配。
问题原因拆解
如果你的DataTable里对应列的类型是double或者float(很多Excel读取库默认会把数值列转成这类二进制浮点数),就会出现这种情况:
- 像
17.85这类十进制小数刚好能被二进制浮点数精确表示,所以插入后显示为17.8500,没问题; - 但
17.86、32.04这类数,用double存储时实际是一个接近但不完全等于原值的二进制近似值,当SqlBulkCopy把它转成SQL的decimal(15,4)时,就会被截断/舍入成17.8599这类“看似错误”的数值。
解决方案
最直接有效的办法就是让DataTable的列类型和SQL表完全匹配,具体操作分两种场景:
1. 手动创建匹配的DataTable(推荐)
如果是从Excel读取数据,别依赖库的自动类型推断,手动创建DataTable并指定列类型为decimal:
// 创建和SQL表结构匹配的DataTable DataTable data = new DataTable(); // 这里的列名、类型要和SQL表对应,decimal类型默认就能匹配decimal(15,4) data.Columns.Add("TargetColumnName", typeof(decimal)); // 从Excel读取数据时,显式转换为decimal再加入行 foreach (var excelRow in myExcelSource) { // 注意:如果Excel里的数值是字符串,要先转成decimal再添加 decimal value = Convert.ToDecimal(excelRow["ExcelColumnName"]); data.Rows.Add(value); } // 再执行BulkCopy bulkCopy.WriteToServer(data);
2. 配置SqlBulkCopy的列映射(备选)
如果没法修改DataTable的列类型,可以在SqlBulkCopy里显式指定目标列的精度和小数位数,强制转换时的规则:
using (var bulkCopy = new SqlBulkCopy(yourConnectionString)) { bulkCopy.DestinationTableName = "YourSQLTableName"; // 添加列映射并指定SQL端的类型参数 var columnMapping = bulkCopy.ColumnMappings.Add("SourceDataColumn", "SQLTargetColumn"); columnMapping.SourceColumnDataType = SqlDbType.Decimal; columnMapping.Precision = 15; columnMapping.Scale = 4; bulkCopy.WriteToServer(data); }
额外验证小技巧
插入前可以遍历DataTable的行,打印一下decimal类型的值,确认和Excel里的原始数值完全一致,避免在读取环节就引入误差。
内容的提问来源于stack exchange,提问作者Micha艂 Woli艅ski
相关产品推荐
相关产品推荐

