ane*_*nge 4 excel vba ado adodb
我正在 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
Run Code Online (Sandbox Code Playgroud)
我想要实现的是在选择中拥有另一列,例如
query = "select t.[Col1], myFunc() from [Sheet1$] As t"
Run Code Online (Sandbox Code Playgroud)
其中 myFunc 是工作簿中定义的函数。
我知道 Access 中可以实现类似的操作(在查询中具有自定义 VBA 函数)。这在 Excel 中也可以实现吗?
对于这种情况,最佳实践或解决方法是什么?
我认为您在这里需要一些基本的解释,也许还需要回答这个问题:
SQL中的函数从哪里来?
如果您将查询发送到任何支持 ANSI 标准 SQL 的数据库服务器,数据库引擎将解析并运行 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 中没有的功能。它们都允许数据库所有者创建自己的函数,这些函数驻留在服务器上并且也可用于 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 数据库引擎的以下功能:使用 VBA:您已经获得了本机 Jet SQL 函数列表,仅此而已
这里列出了这些功能,其他地方很少列出:
该列表现在包括 IIF()- 内联“IF”函数 - 如果您希望在 SELECT 子句中使用 CASE 语句,那么这就是 Jet SQL 中所拥有的全部功能;如果您在本机 Jet-SQL 中的第一课是查询中的所有 VBA NZ() 函数都已停止工作,那么您会发现这很有用。
其中许多函数看起来像熟悉的 VBA 函数:这会造成混淆,因为您运行的不是 VBA,而是 SQL。
很少有人了解这个本机 Jet 函数列表与 MS-Access 提供给 SQL 的本机 VBA 函数列表不同,并且 Microsoft 没有在其文档中明确说明这一点。
这是一个完整的 PITA,因为查询 SQL 服务器或 Oracle DB 的每个人都期望服务器将运行其 SQL 查询中的所有函数,这些函数是在该服务器上运行的 SQL 方言声明、导入或“本机”的。您已在 Access mdb 中声明了 VBA 函数,并且您希望它们也对 SQL 可见!
如何不解决这个问题:
我见过一个 Sybase 服务器,其中聪明但被误导的数据库所有者从外部库导入了函数,您肯定使用过这些函数,但没有意识到它存在于每个 MS-Access 数据库中:vbaen32.dll,VBA 函数枚举 dll。这需要做大量的工作,但从来没有完全奏效:请不要试图复制这一天才的壮举。
所以简短的回答是“不”。
现在给出有用的答案:
Recordset.GetRows() 将以二维 VBA 数组的形式返回记录集,在 SQL 引擎完成排序、过滤和聚合等繁重工作后,您可以在该数组上运行 VBA 函数。
如果您在仅向前游标上按块顺序运行 vba,调用 Recordset.GetRows(Rows:=1024) 直到到达数据末尾,则可以在大型数据集上高效地执行此操作,而不会占用过多的内存。
尽管您可能想问:“我为什么要这样做?”,因为很难想象更好的分析和设计不会揭示更好的解决方案的过程。我,我必须为一个团队实施这个黑客攻击,该团队依赖 Excel 的流程在不断增长的 csv 文件上运行......并且增长到只能由数据库驱动程序读取的 TB 大小。他们工作的环境中需要 2-3 年的持续管理努力才能获得合适的数据库服务器。
如果您是我退出后继承了该特定流程的幸运儿子,我建议您在将该站点从轨道上摧毁后尝试我的 GetRows“解决方案”。
脚注:如果您找到更好的 Jet SQL 函数在线列表,请扩展此答案。
同时,我会敦促任何其他阅读本文的“Stack 贡献者”将自己的链接添加到 Jet SQL 本机函数的良好列表中 - 如果您能找到一个。大多数都是错误的,而且没有一个是全面的,而且很少有人明确指出本机函数和导入的 VBA 之间存在差异。据我所知,Jet 引擎正在从 VBAEN32.dll 导入并运行一组受限制的函数 - 但 ADODB 下的 Jet 绝对不是功能齐全的 VBA 主机应用程序,当您在 MS-Access 之外使用它。