OleDB и смешанные типы данных Excel: отсутствуют данные
у меня есть лист Excel, который я хочу прочитать в datatable - все хорошо, за исключением одного конкретного столбца в моем листе Excel. Столбец "ProductID" представляет собой сочетание значений, таких как ##########
и n#########
.
пробовал пусть OleDB обрабатывает все автоматически, прочитав его в dataset / datatable, но любые значения в "ProductID", такие как n######
отсутствуют, игнорируются и остаются пустыми. Я попытался вручную создать свой DataTable, выполнив цикл через каждую строку с помощью datareader, но с точно такими же результатами.
вот код :
// 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######
. Как я могу это сделать?
6 ответов
используя .Net 4.0 и чтение файлов Excel, у меня была аналогичная проблема с OleDbDataAdapter
- т. е. чтение в смешанном типе данных в столбце " PartID "в MS Excel, где значение PartID может быть числовым (например, 561) или текстовым (например, HL4354), даже если столбец excel был отформатирован как"текст".
из того, что я могу сказать, ADO.NET выбор типа данных на основе большинства значений в столбце (с привязкой к числовому типу данных). т. е. если большинство PartID в наборе образцов числовой, ADO.NET объявит столбец числовым. Поэтому ADO.Net попытается привести каждую ячейку к числу, которое не будет выполнено для значений" text "PartID и не импортирует эти" text " PartID.
моим решением было установить OleDbConnection
connectionstring использовать Extended Properties=IMEX=1;HDR=NO
чтобы указать, что это импорт и что таблица(ы) не будет включать заголовки. Файл excel имеет строку заголовка, поэтому в этом случае скажите ado.net не использовать его. Затем позже в коде удалите эту строку заголовка из dataset и voilà у вас смешанный тип данных для этого столбца.
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")
});
несколько форумов, я нашел утверждение, что путем добавления IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text
для расширенных свойств в строке подключения устранит проблему, но это не так. Я, наконец, решил эту проблему, добавив "HDR=NO" к расширенным свойствам в строке соединения (как показывает Брайан Уэллс выше), чтобы я мог импортировать смешанные типы.
затем я добавил некоторый общий код, чтобы назвать столбцы после первой строки данных, а затем удалить первую строку.
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, рад, что это помогает с проблемой смешанного типа.
столбец DateTime-это целое другое животное, которое, как я помню, вызвало у меня горе в прошлом... у нас есть один файл excel, который мы обрабатываем, что OleDbDataAdapter иногда преобразует даты в двойной тип данных (по-видимому, Excel хранит даты как двойные, которые кодируют количество дней, прошедших с января 0, 1900 ).
обходной путь должен был использовать:
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;
}
}
существует два способа обработки смешанных типов данных и excel.
Способ 1
- откройте электронную таблицу excel и установите формат столбца в нужный формат вручную. В данном случае "текст".
Способ 2
-
есть "hack", который состоит из добавления "IMEX=1" в строку подключения вот так:
Поставщик=Microsoft.Реактивный.Oledb для.4.0;сведения Источник=файл myfile.xls; расширенные свойства=Excel 8.0; IMEX=1
Это попытается обработать смешанные форматы Excel в соответствии с тем, как он установлен в вашем реестре. Это может быть установлено локально вами, но для сервера это, вероятно, не вариант.
@Brian Wells спасибо, ваше предложение сделало трюк, но не полностью... Работал для смешанного поля int-string, но столбцы datetime после этого пошли со странными символами, поэтому я применил "hack" над "hack".
1.- Сделай систему.Ио.Файл.Скопируйте и создайте копию файла excel.
2.- Измените заголовки столбцов Datetime программно во время выполнения на что-то в формате datetime, т. е. "01/01/0001".
3.- Сохраните excel, а затем применить ваш трюк делает запрос с HDR=NO для измененного файла.
сложно, да, но работал, и разумно быстро, если у кого-то есть альтернатива этому, я буду рад услышать.
поздравления.
P. D. извините мой английский, это не мой родной язык.
ярлык --> если у вас есть столбец смешанного типа в Excel: сортируйте столбец Z на
Я в значительной степени прошел все ответы здесь, и некоторые из них работали для меня, а некоторые нет, однако никто не был желателен для меня, потому что каким-то образом ADO не выбирал данные в столбце смешанного типа, который у меня был в моем файле Excel. Я должен был установить HDR=NO
чтобы ADO прочитал мой столбец электронной таблицы, который представляет собой смесь текста и чисел, и таким образом я теряю способность использовать столбец заголовки в моих SQL-операторах, что не очень хорошо. Если порядок столбцов изменяется в файле Excel, инструкция SQL приведет к ошибке или неправильному выводу.
в столбце смешанного типа данных ключом являются первые 8 строк. ADO определяет тип данных для столбца на основе первых 8 строк поэтому, если вы все еще хотите изменить строку подключения с расширенными параметрами, просто отсортируйте столбец Z В A в файле Excel перед чтением данных с помощью ADO, чтобы таким образом строки сверху текст, а затем столбец будет выбран в качестве текста.
Если ваши начальные строки являются числами (независимо от того, установлен ли ваш столбец для форматирования текста в Excel), ADO определит, что столбцы как числовой тип, поэтому, как только он прочитает текстовые строки ниже, он не может привести их в число. В противоположном случае, если столбец определяется текстом, если любая строка, если число, оно может быть приведено как текст.