自定义[h]:mm:ss in Excel"超出范围"对于时间数据类型

时间:2016-06-15 20:25:41

标签: c# sql-server excel visual-studio epplus

使用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();
   }

1 个答案:

答案 0 :(得分:0)

如果我在将文件读入数据表之前显式地强制删除违规列,则可以解决我的问题,并且SQL表中的导入列是时间数据类型。

 using (ExcelRange col = ws.Cells["G:G"])
 {
     col.Style.Numberformat.Format = "HH:mm";
 }

当他们在.xlsx格式化为[h]:mm:ss时,仍然不明白他们作为INT进入的根本原因...