2011-02-24 5 views
1

J'ai un classeur dans lequel plusieurs de mes flux de données transmettent un paramètre dans la requête SQL en fonction de certains menus déroulants/actions de l'utilisateur. Cela permet de conserver l'ajustement du classeur, d'améliorer le calcul, etc. - le fait de conserver tous les détails au niveau de l'élément dans le classeur n'est tout simplement pas pratique.excel vba: pause pour les requêtes SQL paramétrées à compléter?

Certains éléments de ma VBA dépendent des évaluations de données provenant de ces requêtes paramétrées. Ici se pose le problème - VBA n'attend pas que le paramètre soit retransmis à la requête avant d'évaluer tout dans la macro. Je suis curieux de savoir si quelqu'un a des idées ou des conseils sur les meilleures pratiques pour «suspendre» l'exécution de VBA par programmation jusqu'à ce qu'un flux soit actualisé. Mon travail consiste maintenant à découper mon VBA en deux parties, à lancer tout ce qui dépend des données modifiées dans une fonction séparée et à utiliser application.ontime pour faire une pause de X secondes.

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

Ceci est une solution à 90% mais c'est loin d'être idéal. La durée est arbitraire - sur une connexion très lente, elle est insuffisamment longue et sur une connexion rapide elle est inutilement lente.

Idéalement, il y aurait un moyen d'attendre qu'Excel soit prêt et de continuer. Semblable à la façon lors de l'utilisation de la bibliothèque MS Internet contrôles que vous pouvez utiliser

Do Until .document.ReadyState = "complete" 

pour mettre en pause l'exécution jusqu'à ce que IE retourne un état prêt. Des stratégies pour une solution plus élégante?

modifier: par jon ci-dessous, en ajoutant le code et expliquant comment fonctionne requête 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) 

la? est un paramètre qui transmet l'ID d'étudiant concerné - MS query utilise une valeur de cellule pour ce paramètre. la cellule qu'il semble a juste une recherche basée sur ce que l'élève a été sélectionné:

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

(le IfError passe juste un nombre arbitraire pour empêcher les boîtes de dialogue désagréables de sauter vers le haut si une valeur incorrecte obtient en quelque sorte choisi) .

+0

S'il vous plaît pouvez-vous donner un exemple plus de l'appel SQL et le code environnant - Je ne sais pas pourquoi il serait en attente d'exécution. Bravo –

+0

On ne sait pas comment vous exécutez ce SQL - pouvez-vous montrer votre code VBA? Qu'est-ce que vous utilisez exactement pour vos "flux de données"? –

Répondre

2

Votre erreur utilise MS-Query. Codez les appels de base de données à l'aide d'ADODB et attendez la méthode Execute de l'objet ADODB.Command.

... Si c'est ce que vous faites réellement. Il y a une certaine quantité de conjectures ici, mais il semble que l'état de la requête - pas la feuille dans laquelle elle est intégrée - soit l'information dont vous avez besoin.

Ce code appelle une requête SQL de façon asynchrone - il est conceptuellement similaire à un objet de commande, ce qui est (je pense) ce que vous faites réellement - et la boucle brute peut être remplacée par une barre de progression. pour les drapeaux d'interrogation et les calculs ailleurs. FYI, les propriétés d'état et d'état des objets ADO peuvent prêter à confusion. En général, zéro signifie fermer, et 1 signifie ouvert (pour les objets qui renvoient une connexion ouverte ou un jeu de données) et les valeurs supérieures à 1 correspondent à l'attente ou à l'exécution.

Vous pouvez, bien sûr, appeler la requête de manière synchrone.

Je pourrais vous donner du code pour 'DataConnection' mais vous feriez bien mieux d'aller sur ConnectionStrings.com pour cela.

 

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 





[Mise à jour]

Je l'ai appris quelque chose depuis que j'ai posté cette réponse:

Si vous connaissez le nom d'une commande, un rowset- fonction de retour, ou une requête nommée dans une base de données MS-Access, ne vous embêtez pas à l'appeler comme ceci:

 

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

Appelez la commande par son nom et indiquer au moteur de base de données, il est une commande nommée en utilisant la adCmdStoredProc constante:

 

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

Il fonctionne beaucoup, beaucoup plus rapide.

Recherchez le CommandTypeEnum sur MSDN, et l'utilisation tout ce qui fonctionne le mieux pour vous:

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

Utilisez adCmdTable pour les tables nommées, et voir si cela fonctionne mieux que adCmdStoredProc pour les objets « vue » - je J'ai constaté qu'il varie entre les moteurs de base de données.

[/ Mise à jour]

Questions connexes