OleDB和混合Excel数据types:缺less数据

我有一个Excel工作表,我想读入一个数据表 – 除了Excel工作表中的一个特定列以外,一切都很好。 “ProductID”这一列是像##########n#########这样的值的混合。

我试图让OleDB自动处理所有东西,通过读取到数据集/数据表中,但是像' n###### '这样的'ProductID'中的任何值都丢失,忽略并留空。 我尝试通过使用datareader循环每一行手动创build我的DataTable,但具有完全相同的结果。

代码如下:

 // add the column names manually to the datatable as column_1, column_2, ... for (colnum = 0; colnum < num_columns; colnum ++){ ds.Tables["products"].Columns.Add("column_" +colnum , System.Type.GetType("System.String")); } while(myDataReader.Read()){ // loop through each excel row adding a new respective datarow to my datatable DataRow a_row = ds.Tables["products"].NewRow(); for (col = 0; col < num_columns; col ++){ try { a_row[col] = rdr.GetString(col); } catch { a_row[col] = rdr.GetValue(col).ToString(); } } ds.Tables["products"].Rows.Add(a_row); } 

我不明白为什么它不会让我读取像n######这样的值。 我该怎么做?

使用.Net 4.0和读取Excel文件,我有一个类似的问题与OleDbDataAdapter – 即阅读混合的数据types在MS Excel中“PartID”列,其中PartID值可以是数字(例如561)或文本(如HL4354 ),即使excel列被格式化为“文本”。

从我所知道的情况来看,ADO.NET根据列中的大部分值(与数字数据types相关)select数据types。 即如果样本集中的大部分PartID都是数字,则ADO.NET将声明该列为数字。 因此,ADO.Net将尝试将每个单元格转换为一个数字,这将导致“text”PartID值失败,而不会导入这些“text”PartID。

我的解决scheme是将OleDbConnection连接OleDbConnection设置为使用Extended Properties=IMEX=1;HDR=NO表示这是一个导入,并且该表不包含标题。 excel文件有一个标题行,所以在这种情况下告诉ado.net不要使用它。 然后在代码中,从数据集中移除该标题行,并且您已经为该列混合了数据types。

 string sql = "SELECT F1, F2, F3, F4, F5 FROM [sheet1$] WHERE F1 IS NOT NULL"; OleDbConnection connection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PrmPathExcelFile + @";Extended Properties=""Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text"""); OleDbCommand cmd = new OleDbCommand(sql, connection); OleDbDataAdapter da = new OleDbDataAdapter(cmd); DataSet ds = new DataSet(); ds.Tables.Add("xlsImport", "Excel"); da.Fill(ds, "xlsImport"); // Remove the first row (header row) DataRow rowDel = ds.Tables["xlsImport"].Rows[0]; ds.Tables["xlsImport"].Rows.Remove(rowDel); ds.Tables["xlsImport"].Columns[0].ColumnName = "LocationID"; ds.Tables["xlsImport"].Columns[1].ColumnName = "PartID"; ds.Tables["xlsImport"].Columns[2].ColumnName = "Qty"; ds.Tables["xlsImport"].Columns[3].ColumnName = "UserNotes"; ds.Tables["xlsImport"].Columns[4].ColumnName = "UserID"; connection.Close(); 

//现在你可以使用LINQ来search字段

  var data = ds.Tables["xlsImport"].AsEnumerable(); var query = data.Where(x => x.Field<string>("LocationID") == "COOKCOUNTY").Select(x => new Contact { LocationID= x.Field<string>("LocationID"), PartID = x.Field<string>("PartID"), Quantity = x.Field<string>("Qty"), Notes = x.Field<string>("UserNotes"), UserID = x.Field<string>("UserID") }); 

我发现几个论坛声称,通过添加IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text到连接string中的扩展属性将解决问题,但事实并非如此。 我终于通过在连接string的扩展属性中添加“HDR = NO”来解决这个问题(正如Brian Wells上面所示),以便我可以导入混合types。

然后我添加了一些通用代码来命名第一行数据后的列,然后删除第一行。

  public static DataTable ImportMyDataTableFromExcel(string filePath) { DataTable dt = new DataTable(); string fullPath = Path.GetFullPath(filePath); string connString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=\"" + fullPath + "\";" + "Extended Properties=\"Excel 8.0;HDR=No;IMEX=1;\""; string sql = @"SELECT * FROM [sheet1$]"; using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(sql, connString)) { dataAdapter.Fill(dt); } dt = BuildHeadersFromFirstRowThenRemoveFirstRow(dt); return dt; } private static DataTable BuildHeadersFromFirstRowThenRemoveFirstRow(DataTable dt) { DataRow firstRow = dt.Rows[0]; for (int i = 0; i < dt.Columns.Count; i++) { if(!string.IsNullOrWhiteSpace(firstRow[i].ToString())) // handle empty cell dt.Columns[i].ColumnName = firstRow[i].ToString().Trim(); } dt.Rows.RemoveAt(0); return dt; } 

没问题sh4,很高兴它有助于混合types的问题。

DateTime列是整个其他动物,我记得在过去导致我的悲伤…我们有一个Excel文件,我们处理OleDbDataAdapter有时会将date转换为双数据types(显然Excel存储date双打,编码数字自1900年1月0日起经过的天数)。

解决方法是使用:

 OleDbConnection mobjExcelConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + txtExcelFile.Text + @";Extended Properties=""Excel 8.0;IMEX=1;HDR=Yes;"""); OleDbDataAdapter mobjExcelDataAdapter = new OleDbDataAdapter("Select * from [" + txtSheet.Text + "$] where [Supplier ID] <> '' ", mobjExcelConn); DateTime dtShipStatus = DateTime.MinValue; shipStatusOrig = excelRow["Est Ship Date"].ToString(); // excelRow is DataRow in the DataSet via the OleDbDataAdapter if (shipStatusOrig != string.Empty) { // Date may be read in via oledb adapter as a double if (IsNumeric(shipStatusOrig)) { double d = Convert.ToDouble(shipStatusOrig); dtShipStatus = DateTime.FromOADate(d); if (DateTime.TryParse(dtShipStatus.ToString(), out dtShipStatus)) { validDate = true; Debug.WriteLine("{0} converted: ", dtShipStatus.ToString("s")); } } else { if (ValidateShipDate(shipStatusOrig)) { dtShipStatus = DateTime.Parse(shipStatusOrig); validDate = true; Debug.WriteLine("{0} converted: ", dtShipStatus.ToString("s")); } else { validDate = false; MessageBox.Show("Invalid date format in the Excel spreadsheet.\nLine # " + progressBar1.Value + ", the 'Ship Status' value '" + shipStatusOrig + "' is invalid.\nDate should be in a valid date time format.\ne.g. M/DD/YY, MDY, YYYY-MM-DD, etc.", "Invaid Ship Status Date"); } } ... } public static Boolean IsNumeric (Object Expression) { if(Expression == null || Expression is DateTime) return false; if(Expression is Int16 || Expression is Int32 || Expression is Int64 || Expression is Decimal || Expression is Single || Expression is Double || Expression is Boolean) return true; try { if(Expression is string) Double.Parse(Expression as string); else Double.Parse(Expression.ToString()); return true; } catch {} // just dismiss errors but return false return false; } public bool ValidateShipDate(string shipStatus) { DateTime startDate; try { startDate = DateTime.Parse(shipStatus); return true; } catch { return false; } } 

有两种方法可以处理混合的数据types和excel。

方法1

  • 打开你的Excel电子表格,并手动设置列格式为所需的格式。 在这种情况下,“文本”。

方法2

  • 有一个“黑客”组成的附加“IMEX = 1”连接string,如下所示:

    Provider = Microsoft.Jet.OLEDB.4.0; Data Source = myfile.xls;扩展属性= Excel 8.0; IMEX = 1

  • 这将尝试按照在registry中设置的方式来处理混合的Excel格式。 这可以由您本地设置,但对于服务器,这可能不是一个选项。

@Brian Wells谢谢你,你的build议做的伎俩,但不是完全…工作的混合字段intstring,但date时间列与奇怪的字符之后,所以我应用了“黑客”的“黑客” 。

1.-做一个System.Io.File.Copy并创build一个excel文件的副本。

2.-在运行时以编程方式将date时间列标题修改为date时间格式的东西,即“01/01/0001”。

3.保存excel,然后将HDR = NO的查询应用于修改后的文件。

整蛊,是的,但工作,合理快速,如果任何人有其他select,我会很高兴听到。

问候。

PD请原谅我的英语,这不是我的母语。