【问题标题】:OleDbConnection only finds cell value when workbook is also open in Excel当工作簿也在 Excel 中打开时,OleDbConnection 仅查找单元格值
【发布时间】:2014-09-12 19:19:24
【问题描述】:

我有一个程序(实际上是 SSIS 脚本任务,但我认为这并不重要),它创建与 Excel 工作簿的 OLE DB 连接,并读取每个工作表中的单元格值,将它们存储在 SQL Server 表中。

每个工作表都有几个行部分,每个部分代表一个单独的产品。每个产品部分的前两行是四分之一行和一年行。这是一个屏幕截图:

我使用带有“Select *”命令的 OleDbDataReader 将每张工作表中的数据读入 DataTable。我的 SQL 数据库中有一个名为“YearQuarter”的列,其中存储了年份行值和上一季度行值的串联,两个字符串之间有一个连字符:

我的代码是这样的:

  OleDbConnection oleExcelConnection = new OleDbConnection(
        "Provider=Microsoft.ACE.OLEDB.12.0;" +
        "Data Source=" + strWkbkFilePath + ";" +
        "Mode=Read;" +
        "Extended Properties=\"Excel 8.0;HDR=No;IMEX=1\"");

   oleExcelConnection.Open();

   DataTable dtCurrSheet = new DataTable();

   // Name of table is in strLoadTblNm.

    OleDbCommand oleExcelCommand;
    OleDbDataReader oleExcelReader;

    oleExcelCommand = excel_conn.CreateCommand();
    oleExcelCommand.CommandText = "Select * From [" + strLoadTblNm + "]";
    oleExcelCommand.CommandType = CommandType.Text;
    oleExcelReader = oleExcelCommand.ExecuteReader();

    // Load worksheet into data table
    dtSheet.Load(oleExcelReader);

    oleExcelReader.Close();

查看输出数据,我注意到我得到的结果不一致。某些行将具有 YearQuarter 列值,其中仅包含 Year 行值,而其他行将具有两行中的单元格值。例如,我有“2009 - Year End”,后跟“2010”,没有“ - 1st Qtr”。附加到它。

这是因为该四分之一单元格值从未加载到数据读取器中,如 Dataset Visualizer 所示:

另请注意,在数据集中,缺少 Quarter 单元格值的列也有其他数字值缺少格式(无逗号)。

如果我将文件另存为 .csv,则所有单元格值都会保留。

但是,我注意到它并不一致。有时我会运行我的包,而同一行现在将具有全部价值。所以,在上面的例子中,我会得到“2010 - 1st Qtr”。

我终于意识到它可以按预期工作只有在程序运行的同时我碰巧在 Excel 中打开了工作簿

为什么这会有所作为?可能是 Excel 执行的工作簿中存在宏或其他内容,但仅通过 OLE DB 连接访问工作簿时没有?它在 Excel 中执行的事实会影响 OLE DB 获得的数据吗?如果是这种情况,我该如何解决?电子表格已提供给我。所以我不能修改它们。

【问题讨论】:

  • 这不是解决问题的方法,但您是否考虑过导出为 CSV、TXT 或更具可读性的格式?
  • strLoadTblNm的值是多少?
  • 如上所述,如果我将文件保存为 .csv,则所有单元格值都会保留。但是,这不是该项目的选项。说明问题的工作簿在这里:onedrive.live.com/...。如果您下载它,您可以看到示例中的问题单元格 - F12 - 是 DT_R8 而不是 DT_WSTR,这很可能是一个问题。
  • @vba4all - strLoadTblNm 是 .xls 文件的完整文件路径。您可以在此处下载 .xls 文件的副本:onedrive.live.com/…

标签: c# excel ssis oledb


【解决方案1】:

我认为您遇到了 Excel 尝试应用的自动格式设置问题。使用 OLEDB 连接,我看不出打开工作表如何解决您的问题(显然很奇怪)。

尝试将 IMEX = 1 添加到您的连接选项中,以将整个工作表视为文本,看看这是否是您的问题。来自OLEDB connection does not read data from excel sheet 另一个来自外部站点的好帖子:Tips for reading Excel spreadsheets using ADO.NET

此外,您正在从 Excel 工作表中提取数据并将其写入另一个 Excel 工作表...同一个工作簿?我有更多的想法给你,但取决于你的情况。

【讨论】:

  • 我将结果存储在 SQL Server 表中。我试过 IMEX=1。仍然得到相同的结果。您可以在此处下载说明问题的工作簿:onedrive.live.com/…。我刚刚发现示例中的问题单元 - F12 - 是 DT_R8 而不是 DT_WSTR。我现在怀疑这可能是问题所在。
  • 是的.. 我敢打赌你是对的。让我知道。这也可以解释您在数字字段上的格式,有些带有 cmets 有些没有。我已经被这个 Excel 格式的东西烧了很多次了!
  • 你引用的外部文章描述了这个“功能”,即“ADO.NET扫描前8行数据,并据此猜测每一列的数据类型。然后它尝试将该列中的所有数据强制转换为该数据类型,只要强制失败就返回 NULL!”换句话说,它将工作表视为一个关系表,其中给定列中的所有值都属于同一类型。当然,工作表数据不受此限制。哎呀。如文章所述,可以通过修改几个注册表设置来解决此问题。
【解决方案2】:

这个错误原来是一个“功能”,它应该带有一个很大的警告标志。

This article(感谢@vb4all)解释说“ADO.NET 扫描前 8 行数据,并在此基础上猜测每一列的数据类型。然后它会尝试强制从该列到该数据类型的所有数据,在强制失败时返回 NULL!"

换句话说,它将工作表视为一个关系表,其中给定列中的所有值都属于同一类型。当然,工作表数据不受此限制。

可以通过在连接字符串选项中设置 IMEX=1 然后修改这些注册表设置来解决此问题:

Hkey_Local_Machine/Software/Microsoft/Jet/4.0/Engines/Excel/ImportMixedTypes

Hkey_Local_Machine/Software/Microsoft/Jet/4.0/Engines/Excel/Typ

(注意:注册表项因 32 位和 64 位而异。例如,对于 64 位,第一个是 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Jet 4.0)。

我认为这是一个非常冒险的设计,会引发很容易被忽视的数据传输错误。

【讨论】:

  • @vba4all - 就是那个,是的。
  • Connectionstrings.com 有一个解决方法.. 虽然性能不是很好...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 2013-03-26
  • 2012-09-12
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多