C# OleDbConnection仅在工作簿也在Excel中打开时查找单元格值

C# OleDbConnection仅在工作簿也在Excel中打开时查找单元格值,c#,excel,ssis,oledb,C#,Excel,Ssis,Oledb,我有一个程序(实际上是SSIS脚本任务,但我认为这并不重要),它创建到Excel工作簿的OLE DB连接,读取每个工作表中的单元格值,并将它们存储在SQL Server表中 每个工作表都有多个部分的行,每个部分对应一个单独的产品。每个产品部分的前两行是季度行和年度行。以下是屏幕截图: 我使用带有“Select*”命令的OleDbDataReader将每张工作表中的数据读取到数据表中。在我的SQL数据库中有一个名为“YearQuarter”的列,我在其中存储年份行值和前一个季度行值的串联,并在两

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

每个工作表都有多个部分的行,每个部分对应一个单独的产品。每个产品部分的前两行是季度行和年度行。以下是屏幕截图:

我使用带有“Select*”命令的OleDbDataReader将每张工作表中的数据读取到数据表中。在我的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年年底”之后加上“2010年”,后面没有“-1st Qtr.”

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

还请注意,在数据集中,缺少四分之一单元格值的列也有缺少格式的其他数值(无逗号)

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

然而,我注意到它并不一致。有时我会运行我的包,同一行现在会有完整的值。在上面的例子中,我得到了“2010-1st Qtr”

我终于意识到,只有在程序运行的同时,我碰巧在Excel中打开了工作簿,它才能像预期的那样工作


为什么这会有不同?是否工作簿中存在由Excel执行的宏或其他内容,而不是仅通过OLE DB连接访问工作簿?它在Excel中执行的事实会影响OLE DB获得的数据吗?如果是这样的话,我该怎么做?电子表格已经提供给我了。所以我不能修改它们

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

尝试将IMEX=1添加到连接选项中,以将整个工作表视为文本,查看这是否是您的问题。来自外部站点的另一篇好文章:


此外,您正在从excel工作表中提取数据并将其写入另一个excel工作表。。。同一个工作簿?不过,根据你的情况,我还有一些想法要告诉你

这个bug被证明是一个“特性”,它应该带有一个大的警告标志

(谢谢,@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)


我认为这是一个非常危险的设计,会导致数据传输错误,很容易被忽略。

这不是问题的解决方案,但您是否考虑过导出到CSV、TXT或更可读的格式?strLoadTblNm的值是多少?正如我上面解释的,如果我将文件保存为.CSV,所有单元格值都会保留。但是,这不是本项目的一个选项。说明此问题的工作簿如下:onedrive.live.com/…。如果您下载它,您可以看到示例中的问题单元格-F12-是DT_R8而不是DT_WSTR,这可能是一个问题。@vba4all-strLoadTblNm是.xls文件的完整文件路径。您可以在此处下载.xls文件的副本:我将结果存储在SQL Server表中。我试过IMEX=1。仍然得到相同的结果。您可以在此处下载说明问题的工作簿:。我刚刚发现示例中的问题单元F12是DT_R8而不是DT_WSTR。我现在怀疑这可能就是问题所在。。我打赌你是对的。让我知道。这也可以解释数字字段的格式,有些带有注释,有些没有注释。我已经被这个Excel格式的东西烧坏了很多次了!您引用的外部文章描述了此“功能”,即“ADO.NET扫描前8行数据,并在此基础上猜测每列的数据类型。然后它尝试将该列中的所有数据强制转换为该数据类型,每当强制失败时返回NULL!”换句话说,它将工作表视为一个关系表,其中给定列中的所有值都是相同类型的。当然,工作表数据不受此限制。哎呀。这种行为可以通过修改几个注册表设置来解决,正如本文所描述的那样。@vba4all-就是这样,是的。有一个解决办法。。虽然性能不太好。。。