VBA function in Excel ADODB query

I open an ADODB connection in Excel 2007 to query one of the worksheets of the current workbook. When trying to add a custom VBA function, the error calls "<function name w90>". Compound:

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 

What I would like to achieve is to have another column in the selection, e.g.

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

where myFunc is the function defined in the book.

I know that something similar is possible in Access (to execute custom VBA functions in a request). Is this possible in Excel?

What is the best practice or workaround for this scenario?

+4
vba excel-vba excel ado adodb
source share
2 answers

I think you need basic explanations here, and perhaps the answer to this question:

Where do functions come from in SQL?

If you send queries to any database server that supports ANSI-Standard SQL, the database engine will analyze and run the built-in functions that are native to SQL: LEFT (), SUBSTRING (), SIN (), SQR (), etc. d. There is a short list here:

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

Oracle servers will provide additional features that extend ANSI SQL, as well as Microsoft SQL Servers; both PL-SQL and T-SQL have features not available in standard SQL. Both of them allow the database owner to create their own functions that are located on the server and are also available for SQL queries.

Microsoft Jet SQL, which is not quite the same as ANSI SQL, has a fairly limited set of native functions; but no one objects when they run Jet SQL in an MS-Access environment, since almost all Visual Basic for Applications features become available for MS-Access SQL Server.

In addition, all of the VBA functions declared worldwide that they wrote and made visible in the local MS-Access project are also available for the SQL engine.

While you are executing a request from Microsoft Access.

This is the easy part ...

Once you move beyond the MS-Access environment, you will not be able to see VBA.

You can query the data using Jet SQL (and Microsoft.ACE.OLEDB.12.0 provider does just that), but if you use it from Excel, you will not like the MS-Access database engine's ability to use VBA: you have your own list of functions Jet sql and nothing else

Features and very few other places are listed here:

MS Access: Features - List by Category

This list now includes IIF() - the built-in "IF" function is all that you have in Jet SQL if you want the CASE statement in the SELECT clause; You will find this useful if your first lesson in native Jet-SQL is that all the VBA NZ () functions in your query have stopped working.

Many of these functions are similar to the familiar VBA functions: this is a source of confusion because you are not using VBA, you are using SQL .

Very few people realize that this list of Jet native functions does not match the list of VBA native functions available for SQL through MS-Access, and Microsoft does not make this explicit in its documentation.

This is a complete PITA, because everyone who requests a SQL server or Oracle DB expects the server to perform all and any functions in its SQL query that are declared, imported, or native to the SQL dialect running on that server, you declared the VBA functions in Access mdb and you expected them to be visible to SQL too!

How not to fix it:

I saw a Sybase server where a brilliant but erroneous database owner imported functions from an external library that you definitely used, not realizing that it was there in every MS-Access database: vbaen32.dll, dll VBA enumeration functions. It required a lot of work and never worked: please do not try to reproduce this brilliant talent.

So the short answer is no.

Now for a useful answer:

Recordset.GetRows () will return your recordset as a 2-dimensional VBA array, and you can run your VBA functions after that, after the SQL engine has done a heavy lifting of sorting, filtering and aggregation.

You can do this efficiently on a large data set without extra memory, if you run vba in pieces sequentially with the Forward-Only cursor, calling Recordset.GetRows (Rows: = 1024) until you press the end of the data.

Although you may ask, “Why am I doing this?”, Since it is very difficult to think of a process where the best analysis and design will not reveal the best solution. To me, I had to implement this hack for an Excel-dependent team, a process that ran on csv files that grew and grew ... And grew to the size of a terabyte that could only be read by the database driver. And they work in an environment where getting the right database server takes 2-3 years of continuous management effort.

If you are a happy son who inherited this process after I left, I recommend trying GetRows' solution after it has taken the site out of orbit.



Footnote: Please post this answer if you find the best online list for Jet SQL features.

Meanwhile, I would like to encourage any other Stack contributor who reads this to add their own links to the good list of Jet SQL related functions - if you can find it. Most of them are erroneous, and none of them are exhaustive, and very few of them explicitly state that there is a difference between native functions and imported VBA. As far as I know, Jet Engine imports and runs a limited set of functions from VBAEN32.dll, but Jet under ADODB is definitely not a fully functional VBA hosting application, and this restriction should be clearly understood when you use it outside of MS-Access.

+2
source share

I see only 1 option:

Since the function "myFunc ()" does not have any parameters, you can enter this function on a separate sheet (for example, in Sheet2 in A2, put the header as "A" in A1) and refer to the cell in the SQL query as:

 select t.[Col1], myFunc.A from [Sheet1$] As t, [Sheet2$] as myFunc 
+1
source share