2014-08-10 1 views
4

Я открываю соединение ADODB в Excel 2007 для запроса одного из рабочих листов текущей книги. При попытке добавить пользовательскую функцию VBA ошибка вызывает «Неопределенное имя функции». Подключение:Функция VBA в Excel Запрос ADODB

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 

То, что я хотел бы добиться того, чтобы иметь еще один столбец в избранных, как

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

где MyFunc есть функция, определенная в книге.

Я знаю, что что-то подобное возможно в Access (чтобы иметь пользовательские функции VBA в запросе). Возможно ли это в Excel?

Какова наилучшая практика или обходной путь для этого сценария?

+0

Чтобы выяснить, что вопрос: Вы говорите «открытие соединения ADODB в Excel 2007 для запроса одного из рабочих листов текущей книги». Почему вы это делаете? Если вы находитесь в Excel, почему бы не получить доступ к листу напрямую? Тем не менее: ваш «запрос» - это строка. Таким образом, вы можете построить эту строку путем конкатенации по мере необходимости. Если функция myFunc() возвращает строку, то возможно: query = "select t. [Col1]," & myFunc() & "from [Sheet1 $] Как t" - это то, что вы хотите? Если нет, как должна выглядеть строка запроса? –

+0

Axel, спасибо за ваши вопросы! 1.) При работе с большим количеством данных с использованием запросов делает операции и обслуживание более чистыми, более эффективными и быстрыми, чем доступ к ячейкам по отдельности. Особенно, когда речь идет о соединении нескольких листов (или таблиц), группировании и упорядочении по нескольким полям. 2.) Конкатенация строки запроса не является опцией, так как конкатенация оценивает функцию только один раз, прежде чем она будет передана объекту соединения. То, что я хотел бы достичь, - это оценить функцию в каждом прогоне, точно так же, как она работает в любом движке базы данных. – anemgyenge

+0

Если вы пишете запрос в Access, вы можете использовать свои собственные функции VBA. Строка запроса будет выглядеть так: «select field1, myFunc (field2) from table1», и myFunc будет оценивать в каждом раунде фактическое значение field2. – anemgyenge

ответ

2

Я думаю, вам понадобятся некоторые основные объяснения здесь, и, возможно, ответ на этот вопрос:

Где функции в SQL приходят из?

Если вы отправляете запросы на любой сервер базы данных, поддерживающий ANSI-Standard SQL, механизм базы данных будет анализировать и запускать встроенные функции, которые являются родными для SQL: LEFT(), SUBSTRING(), SIN() , SQR() и т.д. Там короткий список здесь:

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

Oracle серверы выставят дополнительные функции, которые расширяют ANSI SQL, как будет сервер Microsoft SQL; как PL-SQL, так и T-SQL имеют функции, недоступные в стандартном SQL. Оба из них позволяют владельцу базы данных создавать свои собственные функции, которые находятся на сервере и также доступны для SQL-запросов.

Microsoft Jet SQL, который не является довольно так же, как ANSI SQL, имеет довольно ограниченный набор собственных функций; но никто не возражает, когда они запускают Jet SQL в среде MS-Access, поскольку почти все функции Visual Basic для приложений становятся доступными для SQL-сервера MS-Access.

Кроме того, все объявленные во всем мире функции VBA, которые они написали и сделали видимыми в локальном проекте MS-Access, также становятся доступными для механизма SQL.

До тех пор, пока вы выполняете запрос из Microsoft Access.

Это легкая часть ...

После того, как вы выйдете из среды MS-Access, вы не можете увидеть VBA.

Вы можете запросить данные с помощью Jet SQL (и Microsoft.ACE.OLEDB.12.0 делает именно это), но, если вы используете его из Excel, вы не сможете использовать способность СУБД MS-Access использовать VBA: у вас есть собственный список функций Jet SQL, и ничего больше

функции перечислены здесь, и очень мало других мест:

MS Access: Functions - Listed by Category

Этот список теперь включает в себя IIF() - на встроенный «IF» функции - что все, что вы попали в Jet SQL, если вам хотите сделать оператор CASE в своем предложении SELECT; вы найдете это полезным, если ваш первый урок в собственном Jet-SQL заключается в том, что все функции VBA NZ() в вашем запросе перестали работать.

Многие из этих функций выглядят как знакомые функции VBA: и это источник путаницы, потому что вы не используете VBA, вы используете SQL.

Очень мало кто понимает, что этот список собственных функций Jet не совпадает с списком собственных функций VBA, доступным для SQL через MS-Access, и Microsoft не делает это явным в своей документации.

Это полный PITA, потому что все запросы на SQL-сервер или Oracle DB ожидают, что сервер будет запускать все и любые функции в своем SQL-запросе, которые объявлены, импортированы или «родны» на диалект SQL, запущенный на этом сервер. Вы объявили функции VBA в Access mdb, и вы ожидали, что они тоже будут видны SQL!

Как не исправить:

Я видел сервер Sybase, где блестящая, но неверная владелец базы данных была импортированные функции из внешней библиотеки, которую определенно используется, не понимая, что она есть в каждом MS- Доступ к базе данных: vbaen32.dll, dll функции перечисления функции VBA. Это потребовало довольно много работы, и никогда не было довольно: пожалуйста, не пытайтесь повторить этот подвиг гения.

Таким образом, короткий ответ «Нет».

Теперь за полезный ответ:

Recordset.GetRows() вернет свой набор записей в качестве 2-мерный массив VBA, и вы можете запустить свои функции VBA в том, что после того, как SQL двигатель сделал тяжелый подъем сортировки, фильтрации и агрегации.

Вы можете сделать это эффективно на большом наборе данных без чрезмерного объема памяти, если вы последовательно запускаете vba в кусках курсором только вперед, вызывая Recordset.GetRows (строки: = 1024), пока не нажмете конец данных.

Хотя вы можете спросить: «Почему я это делаю?», Так как очень сложно думать о процессе, где лучший анализ и дизайн не будут раскрывать лучшего решения. Мне, я должен был реализовать этот взлом для команды, зависящей от Excel, процесса, которая работала на csv-файлах, которые росли и росли ... И выросли до размеров терабайта, которые могли быть прочитаны только драйвером базы данных. И они работают в среде, где получение надлежащего сервера баз данных занимает 2-3 года непрерывного управленческого усилия.

Если вы счастливый сын, который унаследовал этот процесс после того, как я ушел, я рекомендую попробовать свое решение GetRows 'после того, как вы нанесли удар по сайту с орбиты.



Сноска: Do, пожалуйста, расширить этот ответ, если вы найти лучший онлайн листинг функций Jet SQL.

Между тем, я хотел бы призвать любого другого «вкладчика стека», который читает это, чтобы добавить свои собственные ссылки на хороший список родственных функций Jet SQL - если вы можете его найти. Большинство из них ошибочны, и ни один из них не является исчерпывающим, и очень немногие из них явно заявляют, что существует разница между встроенными функциями и импортированным VBA. Насколько мне известно, Jet Engine импортирует и запускает ограниченный набор функций из VBAEN32.dll, но Jet под ADODB определенно не является полнофункциональным хостинговым приложением VBA, и это ограничение должно быть четко понято, когда вы используя его за пределами MS-Access.

1

Я вижу только 1 вариант здесь:

В качестве «MyFunc()» функция не имеет каких-либо параметров, которые вы можете ввести функцию на отдельном листе (например, к Лист2 в А2, в A1 поставить заголовок как «A») и ссылку на ячейку в запросе SQL, как:

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

 Смежные вопросы

  • Нет связанных вопросов^_^