我有一个要读入datatable的Excel工作表-除了Excel工作表中的一个特定列之外,一切都很好。“ProductID”列是像##########
和n#########
这样的值的混合。
我试图通过将其读取到dataset/datatable中来执行let OleDB handle everything by itself automatically,但是像n######
这样的'ProductID‘中的任何值都会丢失、被忽略并留空。我尝试通过使用datareader遍历每一行来手动创建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######
这样的值。我该怎么做呢?
发布于 2011-04-20 03:20:46
在使用Excel4.0和读取.Net文件时,我遇到了类似的OleDbDataAdapter
问题--即在MS Excel中读入" PartID“列的混合数据类型,其中PartID值可以是数字(例如561)或文本(例如HL4354),即使Excel列被格式化为" text”。
据我所知,ADO.NET根据列中的大多数值选择数据类型(与数值数据类型一致)。也就是说,如果样本集中的大部分PartID都是数字,则ADO.NET将声明该列为数字。因此,ADO.Net将尝试将每个单元格转换为一个数字,对于"text“PartID值,这将失败,并且不会导入这些"text”PartID。
我的解决方案是将OleDbConnection
连接字符串设置为使用Extended Properties=IMEX=1;HDR=NO
,以指示这是一个导入,并且表将不包含标头。excel文件有一个标题行,因此在本例中告诉ado.net不要使用它。然后在后面的代码中,从dataset中删除标题行,这样就有了该列的混合数据类型。
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搜索字段了
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")
});
发布于 2012-08-22 05:05:57
我找到的几个论坛声称,通过将IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text
添加到连接字符串中的扩展属性可以解决问题,但事实并非如此。我最终解决了这个问题,将"HDR=NO“添加到连接字符串的扩展属性中(如Brian Wells上面所示),这样我就可以导入混合类型。
然后,我添加了一些通用代码来根据第一行数据命名列,然后删除第一行。
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;
}
发布于 2011-04-29 22:48:46
没有问题的sh4,很高兴它有助于解决混合类型的问题。
DateTime专栏是另一个我记得在过去给我带来悲痛的动物……我们处理了一个excel文件,OleDbDataAdapter有时会将日期转换为double数据类型(显然,Excel将日期存储为double,这是自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, M.D.Y, 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;
}
}
https://stackoverflow.com/questions/3232281
复制相似问题