簡體   English   中英

Excel ADODB查詢中的VBA函數

[英]VBA function in Excel ADODB query

我在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的數據庫服務器發送查詢,數據庫引擎將解析並運行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查詢。

微軟SQL的Jet,這是不完全一樣的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函數列表,沒有別的

這里列出了這些功能,其他地方很少:

MS Access:功能 - 按類別列出

該列表現在包括IIF() - 內聯'IF'函數 - 如果你想在SELECT子句中使用CASE語句,這就是Jet SQL中的所有功能。 如果您在本機Jet-SQL中的第一課是查詢中的所有VBA NZ()函數都已停止工作,那么您會發現它很有用。

其中許多函數看起來都像熟悉的VBA函數:這是一個混亂的來源,因為你沒有運行VBA,你正在運行SQL

很少有人理解這個本機Jet函數列表與MS-Access為SQL提供的本機VBA函數列表不同,並且Microsoft在其文檔中沒有明確說明這一點。

這是一個完整的PITA,因為每個查詢SQL服務器或Oracle數據庫的人都希望服務器運行其SQL查詢中的所有和任何函數,這些函數是在該服務器上運行的SQL的方言中聲明,導入或“本機”的。 您已在Access mdb中聲明了VBA函數,並且您希望它們對SQL也是可見的!

如何解決這個問題:

我見過一個Sybase服務器,其中出色但誤導的數據庫所有者從外部庫中導入了一些你肯定使用過的函數而沒有意識到它存在於每個MS-Access數據庫中:vbaen32.dll,VBA函數枚舉dll。 這需要相當多的工作,而且從來沒有完全奏效:請不要試圖復制這個天才的壯舉。

所以簡短的回答是'不'。

現在有用的答案:

Recordset.GetRows()將返回您的記錄集作為二維VBA數組,並且您可以在SQL引擎完成排序,過濾和聚合的繁重工作之后運行您的VBA函數。

如果在前向光標上按順序運行vba,調用Recordset.GetRows(行:= 1024)直到達到數據末尾,就可以在大型數據集上高效地執行此操作,而不會占用過多的內存。 。

雖然您可能想問:“為什么我這樣做?”,因為很難想到一個更好的分析和設計無法揭示更好的解決方案的過程。 我,我必須為一個團隊實施該攻擊,這個團隊的Excel依賴進程在csv文件上運行,而csv文件的增長和增長......並且增長到TB級,只能由數據庫驅動程序讀取。 他們在一個獲得適當數據庫服務器需要2 - 3年持續管理工作的環境中工作。

如果你是我退出后繼承了這一特定過程的幸運之子,我建議在從軌道上查看網站之后嘗試我的GetRows'解決方案'。



腳注:如果您找到更好的Jet SQL函數在線列表,請展開此答案。

同時,我會敦促其他任何讀取此內容的Stack貢獻者將自己的鏈接添加到Jet SQL本機函數的良好列表中 - 如果可以找到的話。 大多數都是錯誤的,沒有一個是全面的,很少有人明確表示本機功能和導入的VBA之間存在差異。 據我所知,Jet Engine正在從VBAEN32.dll導入並運行一組受限制的功能 - 但ADODB下的Jet肯定不是功能齊全的VBA主機應用程序,當你需要時,需要清楚地理解這個限制在MS-Access之外使用它。

我在這里只看到一個選項:

由於“myFunc()”函數沒有任何參數,您可以將函數輸入到單獨的工作表(例如,在A2中的Sheet2,在A1中放置像“A”這樣的標題)並引用SQL查詢中的單元格,如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM