C# OleDb与Excel的连接;如何选择固定宽度、无限高度?

C# OleDb与Excel的连接;如何选择固定宽度、无限高度?,c#,excel,oledb,C#,Excel,Oledb,我正在使用OleDb从excel电子表格中选择数据。每个电子表格可以包含许多小表格,可能还包括标题和标签等家具。所以它可能看起来像这样,我们有两张桌子和一些标题 A B C D 1 . . . . 2 . . . . 3 Table1 . . .

我正在使用OleDb从excel电子表格中选择数据。每个电子表格可以包含许多小表格,可能还包括标题和标签等家具。所以它可能看起来像这样,我们有两张桌子和一些标题

A B C D 1 . . . . 2 . . . . 3 Table1 . . . 4 Header1 HEADER2 . . 5 h huey . . 6 d dewey . . 7 l loius . . 8 s scrooge . . 9 . . . . 10 . . . . 11 . . . . 12 . . . . 13 . Table 2 . . 14 . HEADER1 HEADER2 HEADER3 15 . 1 foo x 16 . 2 bar y 17 . 3 baz z 18 . . . . 19 . . . . 选择表2中的数据,然后手动检查sentinel行,但这似乎不令人满意。Excel 2003只能读取65535行uint16,但Excel 2007可以读取更多uint32,因此我必须编写代码,根据文件扩展名.xls vs.xls?为Excel 2003和2007提供不同的查询

有人知道一种写查询的方法吗

'选择B14右下方的所有内容'? '选择B->D列中的所有内容' “选择B12:D*”其中*表示“您能做的一切”
两种可能的解决方案:

将表格放在单独的工作表上,然后简单地查询整个工作表。 在Excel 2007中为Excel中的每个表指定一个名称,选择该表,单击鼠标右键,然后选择“命名范围…”,然后在查询中使用此名称而不是Sheet1$B14:D65535。 希望有帮助

编辑

这里有第三个想法:

我不确定您使用什么来查询数据库,但如果您的查询引擎支持Sql Server之类的变量,例如,您可以存储

从服务器名称…表1中选择计数*$

…在一个名为@UsedRowCount的变量中,这将为您提供工作表中实际使用的行数。因此,@UsedRowCount=LastRowUsed-InitialBlankRows


然后,您可能可以使用字符串连接将65535替换为@UsedRowCount+@InitialBlankRows。在您的示例中,您必须将@InitialBlankRows设置为常量,它将是3,因为第一个表的标题行位于第4行。

您说在上一步中,用户选择了标题。谁能说在当前感兴趣的区域下面没有几行空白,后面是另一个不相关的表格?我建议您让他们选择他们感兴趣的整个范围-这应该可以解决这两个问题。

先决条件:您可以在代码中轻松确定最大行数

假设1每次选择都有很大的开销,所以一次选择一行很慢2选择64K或8M行,即使空白很慢。。。所以你想看看中间的某个地方是否更快。试试这个:

选择CHUNKSIZE,例如,如果不这样做,则在运行MAX_行时,每次减少100或1000行。为标记数据结束的空白行扫描每个块。

更新:实际回答明确的问题:

问:有人知道写一个查询的方法吗

Q1:‘选择B14右下方的所有内容’

A1:从[Sheet1$B12:]中选择*不起作用。您必须在Excel2003和Excel2007中执行…B12:IV。但是,您不需要它,因为您知道最右边的列是什么;见下文

Q2:“选择B->D列中的所有内容”

A2:选择 *自[表1$B:D]

Q3:“选择B12:D*”其中*表示“你能做的一切”

A3:从[Sheet1$B12:D]中选择*

使用Python 2.5测试,使用以下代码:

import win32com.client
import sys
filename, sheetname, range = sys.argv[1:4]
DSN= """
    PROVIDER=Microsoft.Jet.OLEDB.4.0;
    DATA SOURCE=%s;
    Extended Properties='Excel 8.0;READONLY=true;IMEX=1';
    """ % filename
conn = win32com.client.Dispatch("ADODB.Connection")
conn.Open(DSN)
rs = win32com.client.Dispatch("ADODB.Recordset")
sql = (
    "SELECT * FROM [Excel 8.0;HDR=NO;IMEX=1;Database=%s;].[%s$%s]"
    % (filename, sheetname, range)
    )
rs.Open(sql, conn)
nrows = 0
while not rs.EOF:
    nrows += 1
    nf = rs.Fields.Count
    values = [rs.Fields.Item(i).Value for i in xrange(nf)]
    print nrows, values
    if not any(value is not None for value in values):
        print "sentinel found"
        break
    rs.MoveNext()
rs.Close()
conn.Close()

我会用约翰一次读1000行的解答

如果安装了Excel,还可以使用OLE自动化

我在Excel中记录了一个简单的宏,用于选择当前表中的最后一个单元格


Sub Macro2()
    Range("B14").Select
    Selection.End(xlDown).Select
    //MsgBox ActiveCell.Address, vbOKOnly
End Sub

现在您只需将其翻译成C并读取活动单元格的地址。

我们阅读了整个电子表格,即:从[Sheet1$]中选择*并处理应用程序代码中的所有其他内容。通过生成的OleDbDataReader很容易到达数据的起点并开始处理


这可能不是从Excel中提取数据的绝对最快的方法,但它是可靠的。

谢谢,丹。不幸的是,我无法控制表单——它们是用户任意输入的,我只需要处理我得到的。明白了。我刚刚在我的答案中添加了第三个想法。删除额外的细节由应用程序处理;我从数据表中读取行,直到数据用完;我得到了一个完整的空白行。然后我自己终止阅读。不幸的是,我不能总是要求用户选择整个范围。在某些情况下,用户为电子表格选择一个标题,其中数据可以更改,但格式不能更改。例如,他们可能有固定标题的股票报价,包括公司、开盘价、收盘价、日期,但实际记录的数量会随着时间的推移而变化。如果他们选择50行,当行数>50时,导入将提供太少的数据。问题中需要的澄清请编辑:1选择一次,运行多个不选择,然后运行*多个。2当你说我从数据表中读取行直到数据用完时,有一个sentinel空白行标记数据的结尾3这是否意味着我从
从[Sheet1$B14:D65535]选择*直到的结果,还是说我选择一行直到?4在代码中确定最大行数是2^16还是2^20有多容易?Excel 2003工作表可以包含65536行,内部编号从0到65535,外部编号从1到65536。

Sub Macro2()
    Range("B14").Select
    Selection.End(xlDown).Select
    //MsgBox ActiveCell.Address, vbOKOnly
End Sub