Excel中的ADODB查询中的VBA函数

我在Excel 2007中打开一个ADODB连接来查询当前工作簿的工作表之一。 当试图添加一个自定义的VBA函数时,错误会引发“未定义的函数名称”。 连接:

Dim connection As String Dim records As ADODB.Recordset Dim query As String Dim fileName As String fileName = ThisWorkbook.FullName connection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & fileName & ";Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1"";" query = "select t.[Col1] from [Sheet1$] As t" Set records = New ADODB.Recordset records.Open query, connection Sheets(2).Range("A1").CopyFromRecordset records 

我想实现的是在select另一列,比如

 query = "select t.[Col1], myFunc() from [Sheet1$] As t" 

myFunc是在工作簿中定义的函数。

我知道在Access中可以这样做(在查询中使用自定义的VBA函数)。 这也可以在Excel中吗?

什么是这种情况下的最佳做法或解决方法?

我想你在这里需要一些基本的解释,也许这个问题的答案是:

SQL中的函数从哪里来?

如果您向任何支持ANSI标准SQL的数据库服务器发送查询,数据库引擎将parsing并运行SQL本地的“内联”函数:LEFT(),SUBSTRING(),SIN(),SQR()等等。这里有一个简短的列表:

http://www.smallsql.de/doc/sql-functions/index.html

Oracle服务器将公开扩展ANSI SQL的其他函数,Microsoft SQL Server也是如此; PL-SQL和T-SQL都具有标准SQL中不可用的function。 它们都允许数据库所有者创build自己的函数,驻留在服务器上,也可用于SQL查询。

Microsoft Jet SQL与ANSI SQL 不太一样,它有一组相当有限的本地函数; 但是当他们在MS-Access环境中运行Jet SQL时没有人介意,因为几乎所有的Visual Basic for Applications函数都可以通过MS-Access用于SQL引擎。

而且,他们编写并在本地MS-Access项目中可见的所有全局声明的VBA函数也可供SQL引擎使用。

只要您从Microsoft Access运行查询。

这是简单的部分…

一旦移到MS-Access环境之外,就看不到VBA。

您可以使用Jet SQL查询数据(而Microsoft.ACE.OLEDB.12.0提供程序正是这样做的),但是,如果您从Excel运行它,则不会享受MS-Access数据库引擎的function使用VBA:你已经有了原生的Jet SQL函数列表,没有别的

function在这里列出,其他地方很less:

MS Access:function – 按类别列出

该列performance在包含IIF() – 内联的“IF”函数 – 如果您希望在SELECT子句中使用CASE语句,那么这就是Jet SQL中的所有function; 如果您在本机Jet-SQL中的第一课是查询中的所有VBA NZ()函数都停止工作,那么您会发现这很有用。

许多这些函数看起来像熟悉的VBA函数:这是一个混乱的来源,因为你没有运行VBA,你正在运行SQL

很less有人知道这个本机Jetfunction列表与MS-Access提供给SQL的本地VBAfunction列表不同,Microsoft并没有在文档中明确指出这一点。

这是一个完整的PITA,因为每个查询SQL服务器或Oracle数据库的人都希望服务器能够在其SQL查询中运行所有和所有在该服务器上运行的SQL方言声明,导入或“原生”的函数。 您已经在Access mdb中声明了VBA函数,并且您也希望它们对SQL可见!

如何解决这个问题:

我已经看到了一个Sybase服务器,其中辉煌但错误的数据库所有者已经从外部库中导入了您已经明确使用的函数,而没有意识到它存在于每个MS-Access数据库中:vbaen32.dll,VBA函数枚举DLL。 这需要相当多的工作,从来没有工作过,请不要试图复制这个天才的壮举。

所以简短的回答是“不”。

现在为有用的答案:

Recordset.GetRows()将以二维VBA数组的forms返回logging集,并且在SQL引擎完成sorting,过滤和聚合的繁重工作之后,您可以运行VBA函数。

你可以在一个大的数据集上有效地完成这个任务,而不会占用过多的内存空间,如果你在一个Forward-Only游标中按顺序运行你的vba,调用Recordset.GetRows(Rows = 1024)直到你碰到数据的末尾。

虽然你可能会问:“我为什么要这样做?”,因为想要一个更好的分析和devise不能提供更好的解决scheme的过程是非常困难的。 我必须为一个团队执行这个攻击,这个团队的Excel依赖进程运行在增长的csv文件上,并且增长到了只能由数据库驱动程序读取的TB级别。 而且他们的工作环境是获得合适的数据库服务器需要2 – 3年的持续pipe理工作。

如果您是我退出后inheritance了特定进程的幸运儿子,我build议您在从轨道上删除站点后尝试GetRows'解决scheme'。

脚注:如果您发现Jet SQLfunction的在线列表更好,请扩展此答案。

同时,我会敦促任何其他的Stack贡献者阅读这个链接,将他们自己的链接添加到Jet SQL原生函数的良好列表中 – 如果可以find的话。 大多数都是错误的,没有一个是全面的,很less有人明确表示原生函数和导入的VBA是有区别的。 据我所知,Jet Engine是从VBAEN32.dll中导入和运行一组受限制的function – 但是在ADODB下的Jet绝对不是一个function齐全的VBA主机应用程序,而且这个限制需要被清楚地理解在MS-Access之外使用它。

我在这里只看到一个选项:

由于“myFunc()”函数没有任何参数,因此可以将函数input到单独的工作表(例如,在A2中的Sheet2中,在A1中放置一个标头,如“A”),并在SQL查询中引用单元格,如:

 select t.[Col1], myFunc.A from [Sheet1$] As t, [Sheet2$] as myFunc