Excel VBA: приостановка для параметризованных запросов SQL для завершения? - PullRequest
1 голос
/ 24 февраля 2011

У меня есть книга, в которой несколько моих фидов данных передают параметр обратно в SQL-запрос в зависимости от выпадающих меню / действий пользователя. Это позволяет обрезать рабочую книгу, улучшать вычисления и т. Д. - хранить все детали на уровне элементов локально в рабочей книге просто не практично.

Некоторые элементы моего VBA зависят от оценки данных, полученных из этих параметризованных запросов. Здесь возникает проблема - VBA не ожидает передачи параметра обратно в запрос, прежде чем оценивать все в макросе.

Мне любопытно, есть ли у кого-нибудь какие-либо мысли или советы о передовых методах программной «приостановки» выполнения VBA до обновления канала. Моя работа сейчас состоит в том, чтобы разделить мой VBA на две части, выбросить все, что зависит от измененных данных, в отдельную функцию и использовать application.ontime, чтобы сделать паузу на X секунд.

Application.OnTime Now + TimeSerial(0, 0, 10), "Restart"

это 90% решение, но оно не идеально. Продолжительность произвольная - на очень медленном соединении оно недостаточно длинное, а на быстром - излишне медленное.

В идеале должен быть какой-то способ подождать, пока Excel не будет готов, а затем продолжить. Аналогично тому, как при использовании библиотеки MS Internet Controls вы можете использовать

Do Until .document.ReadyState = "complete"

приостановить выполнение, пока IE не вернет состояние готовности. Какие-нибудь стратегии для более изящного решения?

изменить: за Джон ниже, добавив код и объясняя, как работает запрос SQL:

select sts1.studentid, sts1.alphascore as testcycle, 
sts2.numscore as lexile, sts3.alphascore as gleq, sts4.numscore as nce

from ps.studenttestscore sts1
join ps.students stu on (sts1.studentid = stu.id)
join ps.studenttestscore sts2 on (sts1.studenttestid = sts2.studenttestid)
join ps.studenttestscore sts3 on (sts1.studenttestid = sts3.studenttestid)
join ps.studenttestscore sts4 on (sts1.studenttestid = sts4.studenttestid)

where (stu.id = ? ) and (sts1.testscoreid = 578) and (sts2.testscoreid = 575) 
and (sts3.testscoreid = 577) and (sts4.testscoreid = 576)

? является параметром, который передает соответствующий идентификатор студента - запрос MS использует значение ячейки для этого параметра. ячейка, на которую она смотрит, просто имеет поиск на основе того, какой студент был выбран:

=IFERROR(INDEX(Stu!$B:$F,MATCH(Student!B2,Stu!$F:$F,0),1),999999)

(iferror просто пропускает произвольное число, чтобы предотвратить появление неприятных диалоговых окон, если каким-либо образом выбрано неправильное значение).

1 Ответ

2 голосов
/ 08 марта 2011

Ваша ошибка в использовании MS-Query. Закодируйте вызовы базы данных, используя ADODB, и дождитесь метода Execute объекта ADODB.Command.

... Если это то, что вы на самом деле делаете. Здесь есть определенное количество догадок, но похоже, что информация запроса, а не лист, в который он встроен, - это информация, которая вам нужна.

Этот код вызывает SQL-запрос асинхронно - он концептуально похож на командный объект, который является (я думаю) тем, что вы на самом деле делаете, - и грубый цикл «сна» можно заменить индикатором выполнения или кодом флаги опроса и вычисления в другом месте.

К вашему сведению, свойства состояния и состояния объектов ADO могут сбивать с толку. В общем случае ноль означает закрытие, а 1 означает открытие (для объектов, которые возвращают открытое соединение или набор данных), а значения выше 1 соответствуют ожиданию или выполнению.

Конечно, вы можете просто вызвать запрос синхронно.

Я мог бы дать вам код для 'DataConnection', но вам гораздо лучше пойти на ConnectionStrings.com для этого.


Public Function FetchRecordSet(SQL As String, Optional CursorType As CursorTypeEnum = adOpenForwardOnly) As ADODB.Recordset
On Error Resume Next

Set FetchRecordSet = New ADODB.Recordset

With FetchRecordSet

    .CacheSize = 8
    Set .ActiveConnection = DataConnection
    .Open SQL, , CursorType, adLockReadOnly, adCmdText + adAsyncFetch

    Do While .State > 1
        Application.StatusBar = "Retrieving data... " 
        Sleep 250
    Loop

End With

Application.StatusBar = False

End Function





[Обновить]

Я кое-что узнал с тех пор, как опубликовал этот ответ:

Если вам известно имя команды, функции, возвращающей набор строк, или именованный запрос в базе данных MS-Access, не беспокойтесь о ее вызове следующим образом:


    SQL = "SELECT * FROM MyQuery"
    .Open SQL, , CursorType, adLockReadOnly, adCmdText + adAsyncFetch

Вызовите команду по имени и скажите ядру базы данных, что это именованная команда, используя константу adCmdStoredProc:


    SQL = "MyQuery"
    .Open SQL, , CursorType, adLockReadOnly, adCmdStoredProc + adAsyncFetch

Он работает намного, намного быстрее.

Найдите CommandTypeEnum в MSDN и используйте все, что вам подходит:

https://msdn.microsoft.com/en-us/library/ms675946(v=vs.85).aspx

Используйте adCmdTable для именованных таблиц и посмотрите, работает ли это лучше, чем adCmdStoredProc для объектов 'view' - я обнаружил, что это зависит от механизмов баз данных.

[/ Update]

...