【问题标题】:Reading an Excel sheet using ADO/ODBC in Delphi 7在 Delphi 7 中使用 ADO/ODBC 读取 Excel 表
【发布时间】:2016-01-05 07:35:34
【问题描述】:

我正在尝试使用 Delphi 7 从内存中的 XLS 或 XLSX 文件中读取 Excel 工作表。如果可能,我会使用自动化来逐个读取单元格,但是当未安装 Excel 时,我会恢复使用 ADO /ODBC Jet 驱动程序。 我使用任一连接

Provider=Microsoft.Jet.OLEDB.4.0; Data Source=file.xls;Extended Properties="Excel 8.0;Persist Security Info=False;IMEX=1;HDR=No";
Provider=Microsoft.ACE.OLEDB.12.0; Data Source=file.xlsx;Extended Properties="Excel 12.0;Persist Security Info=False;IMEX=1;HDR=No";

我的问题是当我使用以下查询时:

SELECT * FROM [SheetName$]

返回的结果不包含空行或空列,因此如果工作表包含此类行或列,则以下单元格会移动,并且不会在正确的位置结束。我需要“按原样”加载工作表,即确切地知道每个值来自哪个单元格位置。

我尝试通过发出一个表单查询来逐个读取单元格

SELECT F1 FROM `SheetName$A1:A1`

但现在驱动程序返回一个错误,提示“在所选区域之外有数据”。顺便说一句,我不得不使用反引号将名称括起来,因为使用像 [SheetName$A1:A1] 这样的括号会发出语法错误消息。

有没有办法告诉驱动程序按原样选择工作表而不跳过空白?或者也许是一种知道每个值从哪个单元格位置返回的方法?

出于内部政策原因(我知道它们不好,但我不决定这些),不可能使用第三方库,我真的需要它来使用标准的 Delphi 7 组件。

【问题讨论】:

  • 你能展示一个这样的excel表的小例子,以及你所说的空行吗?我不确定你到底想要什么......顺便说一句,你试过删除 IMEX=1 吗?这也应该返回空白行。
  • 很遗憾我不能给你一个真实的例子,因为这些都不是“小”,这是问题的核心(另一个问题是实际数据是机密的......);数据没有很好地按列排列。例如,“D”列首先包含 5 行文本,然后是徽标,然后是我需要提取的一些数据行,然后是一些文本,然后是我需要提取的更多数据,等等... IMEX= 0 将不起作用,因为该列包含混合类型。

标签: excel delphi odbc delphi-7 ado


【解决方案1】:

我假设如果您的数据在 B2:D10 范围内,您希望将 A 列作为空列包含在内?可能是?那是对的吗?如果是这种情况,那么当您读取工作表 (SELECT * FROM [SheetName$]) 时,您的数据集也将返回 100 万行乘 16K 列!

您能否不执行如下查询:SELECT * FROM [SheetName$B2:D10] 并使用 ADO GetRows 函数获取一个数组 - 这将为您提供数据的大小。然后你可以索引到数组中得到你想要的数据吗?

【讨论】:

  • 我确实想要首先对应于第 1 行的记录(有 4 个空/空/空白/任何字段),然后是对应于第 2->10 行的 A->D 列的 4 个值的 9 个记录,第一个总是空的。当然,我不想要不在工作表中的行和列,即我想要从自动化 Worksheets[n].UsedRange 获得的列范围。我需要一些时间来试验您的解决方案,因为我目前使用的是 TAdoDataset,而不是底层的 ADO COM 对象。
【解决方案2】:

好的,正确答案是

不管你的老板怎么说,都使用第三方库。甚至不 试试 ODBC/ADO 加载任意 Excel 文件,迟早会碰壁。

它可能适用于包含单个数据表的 excel 文件,但当您想在主要供人类消费的工作表中挑选数据时(即,单列包含一些带有介绍性文本的单元格,一些带有数字数据的单元格,一些带有 cmets 等...)

  • 使用IMEX=1 会忽略空行和空列
  • 使用IMEX=0 有时不再忽略空行,但现在一些第一个非空单元格被视为字段名称而不是数据,尽管HDR=No。无论如何都行不通,因为列中的值属于混合类型。
  • 显式循环跨单元格并生成 SELECT * FROM [SheetName$A1:A1] 一直有效,直到您到达一个空单元格,然后您会遇到访问冲突(见下文)

Access violation at address 1B30B3E3 in module 'msexcl40.dll'. Read of address 00000000

我太老了,不想尝试猜测要使用的适当值,因此它可以工作,直到有人在列中提供另一种数据组合。很抱歉浪费了大家的时间。

【讨论】:

    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多