使用C#(Visual Studio 14.0,.NET 4.6)处理ETL进程以将.xlsx文件导入SQL Server,以及EPPlus库(OfficeOpenXml,不能使用OLEDB作为源文件包含多于最多255列)。我在.xlsx文件中有几个时间列,它们具有自定义[h]:mm:ss格式。遇到加载到SQL中的问题,包括时间和字符串数据类型。
例如,值显示" 14:07:00"在小区和" 2:13:00 PM"在公式栏中。当SQL目标表数据类型为time时,它会抛出异常:
SqlDbType.Time溢出。价值' 00.00:00:00'超出范围。必须在00:00:00.0000000和23:59:59.9999999之间。
如果我将目标数据类型更改为varchar,它只会导入" 14"而不是其余的字符串。它似乎只是在第一个冒号之前识别[h]数字。不确定这是否相关,但复制此单元格并在Excel中粘贴值将返回0.59,当我将单元格格式更改回时,它将转换回14:07:00。将文件另存为.csv并在文本编辑器中打开会生成" 14:07:00"。
我查找了这个特定问题的变体或导入包含冒号的字符串的问题,但是没有找到很多洞察力。有谁知道这里发生了什么?如何以编程方式修复此问题,即不手动更改源中的数据类型?
*编辑:
Here's the time formatting in Excel of the source files:
读取.xlsx的代码:
public static DataSet ReadExcelFile(string filePath, bool hasHeader = true)
{
DataSet ds = new DataSet();
using (var pck = new ExcelPackage())
{
using (var stream = File.OpenRead(filePath))
{
pck.Load(stream);
}
int startSheet = 1;
var ws = pck.Workbook.Worksheets[startSheet];
int totalSheets = ws.Workbook.Worksheets.Count;
for (int sheetNum = startSheet; sheetNum <= totalSheets; sheetNum++)
{
var workSheet = pck.Workbook.Worksheets[sheetNum];
var sheetName = pck.Workbook.Worksheets[sheetNum].Name;
DataTable dt = new DataTable(sheetName);
int totalCols = workSheet.Dimension.End.Column;
int totalRows = workSheet.Dimension.End.Row;
int startRow = hasHeader ? 2 : 1;
ExcelRange wsRow;
DataRow dr;
foreach (var firstRowCell in workSheet.Cells[1, 1, 1, totalCols])
{
dt.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
for (int rowNum = startRow; rowNum <= totalRows; rowNum++)
{
wsRow = workSheet.Cells[rowNum, 1, rowNum, totalCols];
dr = dt.NewRow();
var text = "";
foreach (var cell in wsRow)
{
text = cell.Text;
dr[cell.Start.Column - 1] = cell.Text;
}
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
}
return ds;
}
}
写入SQL表的代码:
public static void WriteTables(string excelFilePath)
{
DataSet data = ReadExcelFile(excelFilePath);
SqlConnection sqlConn = new SqlConnection(Globals.sqlConnectionString);
sqlConn.Open();
foreach (DataTable dt in data.Tables)
{
if (dt.TableName.Equals(ExcelSheets.Base))
{
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(Globals.sqlConnectionString);
sqlBulkCopy.DestinationTableName = sqlTables.Base;
InsertDataTable(sqlBulkCopy, sqlConn, dt);
}
//...iterates through each sheet/table
}
sqlConn.Close();
}
protected static void InsertDataTable(SqlBulkCopy sqlBulkCopy, SqlConnection sqlConnection, DataTable dataTable)
{
sqlBulkCopy.WriteToServer(dataTable);
dataTable.Rows.Clear();
}
答案 0 :(得分:0)
如果我在将文件读入数据表之前显式地强制删除违规列,则可以解决我的问题,并且SQL表中的导入列是时间数据类型。
using (ExcelRange col = ws.Cells["G:G"])
{
col.Style.Numberformat.Format = "HH:mm";
}
当他们在.xlsx格式化为[h]:mm:ss时,仍然不明白他们作为INT进入的根本原因...