OleDb连接到Excel; 我如何select固定宽度,无限高度?

我使用OleDb从Excel电子表格中select数据。 每个电子表格可以包含许多小表,并可能包含标题和标签之类的家具。 所以它可能看起来像这样,我们有两张桌子和一些标题;

             A B C D
     1。  。  。  。
     2。  。  。  。
     3表1。  。  。
     4 Header1 HEADER2。  。
     5 h huey。  。
     6 d杜威。  。
     7 l loius。  。
     8 s sc。。  。
     9。  。  。  。
     10。  。  。  。
     11。  。  。  。
     12。  。  。  。
     13。 表2  。
     14。  HEADER1 HEADER2 HEADER3
     15。  1 foo x
     16。  2巴y
     17。  3 baz z
     18。  。  。  。
     19。  。  。  。

在之前的步骤中,用户已经select了他们感兴趣的表格的标题; 在这种情况下,看表2他们将select范围B14:D14

这些设置被保存,然后我需要查询该表。 随着电子表格数据的更新,可能会一遍又一遍地发生; 任何时候都可以添加更多的行,但是标题总是固定的。 有一个标记(空白行)标记数据的结束

要select表中的数据,我正在写这样的查询;

 SELECT * FROM [Sheet1$B14:D65535] 

select表2中的数据,然后手动检查哨兵行,但这似乎并不令人满意。 Excel 2003只能读取65,535行(uint16),但是Excel 2007可以读取更多(uint32),因此我必须编写代码,以便根据文件的扩展名(.xls和.xls)为Excel 2003和2007提供不同的查询。 XLS?)。

有谁知道一种方式来写一个查询说:

  • “select所有的东西,B14的权利?
  • 'select列B-> D'
  • 'select B12:D *'其中*表示“所有你可以做的”

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

假设(1)每个SELECT有很大的开销,所以一次select一行很慢(2)select64K或8M行(即使是空白)很慢…所以你想看看在中间的某个地方是否可以更快。 尝试这个:

一次selectCHUNKSIZE(例如100或1000)行(更less的情况下,否则会超出MAX_ROWS)。 扫描每个块的空白行标记数据结束。

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

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

Q1:“selectB14的所有东西”?

A1: select * from [Sheet1$B12:]不起作用。 你将不得不做...B12:IV在Excel 2003中,而不pipe它在Excel 2007中。但是,你不需要这样做,因为你知道你最右边的列是什么; 见下文。

Q2:select列B-> D中的所有内容

A2: select * from [Sheet1$B:D]

问题3:'selectB12:D * '其中*表示“所有你可以做的”

A3:select * from [Sheet1 $ B12:D]

使用以下代码testingPython 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() 

情侣可能的解决

  1. 把你的表放在单独的工作表上,然后简单地查询整个工作表。
  2. 为Excel中的每个表提供一个名称(在Excel 2007中,select该表,右键单击并select“命名范围…”),然后在查询中使用该名称而不是“Sheet1 $ B14:D65535”。

希望有所帮助。

编辑

这是第三个想法:

我不知道你用什么来查询你的数据库,但如果你的查询引擎支持variables(如Sql Server,例如),你可以存储的结果…

SELECT COUNT(*)FROM NameOfServer … Sheet1 $

…在一个名为@UsedRowCount的variables中,它会给你在工作表中实际使用的行数。 所以,@UsedRowCount = LastRowUsed – InitialBlankRows。

然后,您可以使用string连接来将“65535”replace为@UsedRowCount + @InitialBlankRows。 你将不得不将@InitialBlankRows设置为一个常量(在你的例子中,这将是3,因为第一个表的标题行位于第4行)。

你说在上一步中,用户已经select了标题。 谁会说在目前的利益地区之下,有不less的空白的行跟着另一个不相关的表呢? 我build议你让他们select他们感兴趣的整个范围 – 这应该解决这两个问题。

我会用John的解决scheme(一次读1000行)。

如果你安装了Excel,你也可以使用OLE自动化。

我已经logging了一个简单的macros,在Excel中select当前表中的最后一个单元格。

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

现在,您只需要在C#中将其翻译并读取活动单元格的地址即可。

我们阅读整个电子表格(即:SELECT * FROM [Sheet1 $]),并处理我们应用程序代码中的所有其他内容。 通过OleDbDataReader进行竞争以获取数据的起始点并开始处理非常简单。

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