如何避免C#中SqlBulkCopy向SQL Server导入时的小数舍入问题?
问题分析与解决
当前遇到的小数被舍入问题,核心源于两个关键问题:
- 原始CSV读取代码存在逻辑错误,导致数据读取不完整
- DataTable未明确指定列类型为字符串,加上目标表可能使用数值类型,引发自动转换导致舍入
具体修正步骤
1. 修复CSV读取的逻辑错误
原代码中foreach循环内定义的col是局部变量,循环结束后仅会添加最后一行数据;同时读取的lines包含表头行,会导致表头被当作数据插入。需要调整读取逻辑,跳过表头并正确遍历每一行数据。
2. 强制DataTable所有列为字符串类型
因为需要保留CSV中的原始值(同一列可能混合文本和小数),必须将DataTable的每一列都设置为string类型,避免.NET自动推断数据类型引发的转换问题。
3. 确认目标表列类型
SQL Server的Mappingtable中所有列必须设置为varchar或nvarchar类型,不能使用数值类型(如int、decimal等),否则即使传入字符串,SQL Server也会自动转换,导致小数舍入或数据丢失。
修正后的完整代码
DataTable csvData = new DataTable(); string csvFilePath = "你的CSV文件路径"; // 替换为实际路径 // 读取表头并创建字符串类型的列 string headline = File.ReadLines(csvFilePath).ElementAt(0); string[] headerLine = headline.Split(','); foreach (string header in headerLine) { // 明确指定列类型为字符串 csvData.Columns.Add(header, typeof(string)); } // 读取数据行(跳过第一行表头) string[] lines = File.ReadAllLines(csvFilePath); for (int i = 1; i < lines.Length; i++) { string line = lines[i]; string[] cols = line.Split(','); // 确保列数匹配,避免索引越界 if (cols.Length == headerLine.Length) { csvData.Rows.Add(cols); } } // 执行批量插入 using (SqlConnection objConn = new SqlConnection(ConfigurationManager.ConnectionStrings["Live"].ConnectionString)) { objConn.Open(); using (SqlBulkCopy objbulkinsert = new SqlBulkCopy(objConn)) { objbulkinsert.DestinationTableName = "Mappingtable"; // 映射列(确保目标表列名与CSV表头一致) foreach (DataColumn column in csvData.Columns) { objbulkinsert.ColumnMappings.Add(column.ColumnName, column.ColumnName); } objbulkinsert.BulkCopyTimeout = 0; objbulkinsert.WriteToServer(csvData); } }
额外注意事项
- 如果CSV中包含带逗号的字段(如
"abc,def"),直接用Split(',')会拆分错误,建议使用专门的CSV解析库处理复杂CSV格式 - 验证目标表的列长度是否足够容纳CSV中的最长内容,避免截断
内容的提问来源于stack exchange,提问作者Gowsi
相关产品推荐
相关产品推荐

