[VBA] fonction paramétré renvoyant le résultat d'une requête ACCESS

fonction paramétré renvoyant le résultat d'une requête ACCESS [VBA] - VB/VBA/VBS - Programmation

Marsh Posté le 21-02-2013 à 17:13:49    

Bonjour,
 
J'ai une base de donnée sous ACCESS contenant des informations que je souhaiterai pouvoir exploiter dans des pages excel.
 
Pour illustrer mon propos, je vous propose un exemple simplifiant beaucoup les choses.
Soit une table:
 
Société1 DatedeCréation
Société2 DatedeCréation
Société3 DatedeCréation
Société4 DatedeCréation
Société5 DatedeCréation
Société6 DatedeCréation
 
Ainsi,  pour obtenir la date de création d'une société, j'ai créé une requête sur ACCESS qui me demande en argument le nom d'une société (et qui fonctionne très bien).
J'aurai donc souhaité créer une fonction VBA prenant en argument le nom de la société et me renvoyant dans ma cellule la date de création de la société.
 
C'est surement très simple, mais cela fait maintenant plusieurs heures que je cherche sans trouver de réponse.
 
Merci pour votre aide.

Reply

Marsh Posté le 21-02-2013 à 17:13:49   

Reply

Marsh Posté le 22-02-2013 à 09:58:27    

Tiens, c'est marrant, je bosse sur du VBA/Access en ce moment :o
 
Pour commencer, il faut que tu ajoute les références qui vont bien dans ton vba:
Microsoft DAO 3.6 Object Library
Peut etre que tu aura besoin aussi de ClFileSearch, un petit coup de google t'en diras plus :o
 
Ensuite, dans le code de ta fonction, il faut que tu paramètre certaines choses:
ta base de donnée: dim db as dao.Database
ton recordset (set de données bdd): dim rstNomSociete as dao.Recordset
ta requête d'extraction: dim sRequete as string
 
'Stocker le chemin de ta base de donnée dans une variable cheminBdd
 
'Ouvrir ta bdd:
set db = DBEngine.Opendatabase(cheminBdd)
 
'Construire ta requête Access (ie: en language SQL, quasiment le même que celui généré par l'assistant requête d'access)
sRequete = "SELECT nomtable.DateCreation FROM nomtable WHERE nomtable.NomSociété =" & ... (iiiha, bienvenue dans la gestion des string, google est ton ami)
 
'Parametrer l'objet requête
Set rstNomSociete = db.OpenRecordset(sRequete)
 
'Récupérer le resultat
Do Until rstNomSociete.EOF
    nomfonction = rstNomSociete![NomChampsquivabien]
    rstNomSociete.MoveNext
Loop
 
'On dit au revoir:
rstNomSociete.Close
db.close
 
Valà, t'as de quoi faire,
En fonction de ton niveau en programmation, ça te prendra entre 3 et 300 minutes à tester :o

Reply

Marsh Posté le 22-02-2013 à 10:18:44    

C'est pas si simple que ça en fait.
Bon, je m'y mets. Je me plonge dedans.
 
Merci pour la réponse. Rendez vous dans 300 minutes.

Reply

Marsh Posté le 22-02-2013 à 10:22:46    

Oui je m'en doute :)
Mais commence par tester 1 seul acces à la base pour 1 requête :)
C'est le plus dur,
Ensuite, ça va tout seul.
SI je peux me permettre: je pense que chercher des sociétés par le nom est risqué (aurtographe...)
Essaye de fonctionner par id plutôt (clés uniques)
 
Enfin, pour la constuction de ta requête, j'imagine que t'as pas mal de tables, rencarde toi sur les inner join. Et pour finir, ton meilleur ami dans ces cas là (après google) c'est l'assitant création de requêtes ;)

Reply

Marsh Posté le 22-02-2013 à 11:32:14    

Bon bon bon,
Je me suis lancé. Et pas de problème pour le code. Je me documente donc c'est super, j'apprends plein de truc.  
 
Entre la concaténation de chaine de caractère, la fonction .EOF (très utile ce truc d'ailleurs),  la connexion à la base de données etc.
 
En revanche, je ne suis pas sur d'avoir saisi l'essentiel.
C'est à dire la petite boucle
 
Do Until rstNomSociete.EOF  
    nomfonction = rstNomSociete![NomChampsquivabien]  
    rstNomSociete.MoveNext  
Loop  
 
 
nomfonction ? C'est quoi ? c'est nomSociete dont tu voulais parler ?
et NomChampsquivabien, c'est bien le champ contenant les dates.  
 
Appelons le ChampsDatedeCreation. C'est ça ou je suis à coté de la plaque ?
 
Enfin bon, j'avance doucement mais surement.  
 
Pour les noms de sociétés, leur clé est en fait leur nom court et il n'y en a que quelques unes. Donc ce n'est pas génant.
Merci pour les inner join, je vais en effet l'utiliser maintenant que tu m'as glissé l'idée.
 
 
Bref, merci beaucoup pour m'avoir mis sur la voie. Je ne m'en sortais pas sinon.

Reply

Marsh Posté le 22-02-2013 à 11:44:50    

Pas de problème, j'ai moi même passé mon niveau de zero à opérationnel sur la partie gestion de base de donnée, une fois les clés de base en main (sans jeu de mot), c'est assez facile, je continue d'être confronté à des petits bugs, mais ça se passe bien :o

le petit bleu a écrit :

Bon bon bon,
En revanche, je ne suis pas sur d'avoir saisi l'essentiel.
C'est à dire la petite boucle 1
 
Do Until rstNomSociete.EOF  
    nomfonction = rstNomSociete![NomChampsquivabien]  
    rstNomSociete.MoveNext  
Loop  
 
 
nomfonction ? C'est quoi ? c'est nomSociete dont tu voulais parler ? 2
et NomChampsquivabien, c'est bien le champ contenant les dates.  
 
Appelons le ChampsDatedeCreation. C'est ça ou je suis à coté de la plaque ? 3


1- En fait, quand tu fait une requête sus acces, tu as un certain nombre de resultats répondant à tes critères.
Imagine que tu cherche non pas une société mais les sociétés ayant + de 5 ans d'existance, tu auras donc N résultats.
CHAQUE resultat est un recordset (littéralement, set de données, soit une ligne de ta table sociétés)
La boucle permet de les lire tous, car ils arrivent 1 par 1
Dans ton cas, tu cherche 1 société par sa clé (nom de société), à priori tu aura 0 ou 1 résultat, la boucle ne semble pas avoir de sens mais elle permet d'éviter un bug en cas de rst vide (enfin, je pense, tu peux tester sans et nous dire ce que ça donne)
2-Dans ton premier post, tu parle de créer une fonction vba :)
c'est donc le nom de ta fonction.
EN vba, tu la déclare:
function recupDateCrea(nomsociete as string) as date
   'code qui cherche la date sur access
   'quand il  la trouve, on entre le résultat dans la fonction
   recupDateCrea = xxxx 'avec xxxx la date de création récupérée par ton code
 
end function
 
Ainsi, dans une cellule tu pourra mettre: =recupDateCrea(nomSocieteCourt) (ou pointer sur une cellule avec le nom recherché)
Et tu aura ton résultat dans la cellule :)
 
3-C'est le nom du champs dans la base, exactement comme il est entré, c'est bien ChampsDatedeCreation
 
:jap:

Reply

Marsh Posté le 22-02-2013 à 11:47:45    

C'est bon ça marche !!
 
Comme quoi je suis bete, j'ai posé ma question trop vite. Un énorme merci !
 
bref, c'est super. Je vais pouvoir me lancer sur des trucs plus compliqués maintenant que je sais que c'est possible.
 
<3
 
Encore merci.
 

Reply

Marsh Posté le 22-02-2013 à 11:51:27    

Pas de problème, juste tiens nous au courant de comment ça marche.
Résoudre un problème, c'est bien, laisser une trace pour les suivants, c'est bien mieux :o

Reply

Marsh Posté le 22-02-2013 à 12:05:12    

Alors pour le coup, c'est mot pour mot ce que tu as écris. Donc il suffit vraiment de recopier et d'adapter.
J'ai fait une procédure pour tester. Donc la boucle est ainsi :  
 
Do Until rstNomEntreprise.EOF
    DateCreation = rstNomEntreprise![DateCreation]
    rstNomEntreprise.MoveNext
Loop
 
 
Juste pour la concaténation de caractère :
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM ENTREPRISES WHERE (((ENTREPRISE.NomCourt)="
sRequete = sRequete & Chr$(34) & nomFond & Chr$(34) & " ))"
 
' Chr$(34) : correspond aux guillemets nécessaire pour la requête.
 
Sinon tout le reste, c'est un one shot. Tout est correct.

Reply

Marsh Posté le 22-02-2013 à 12:18:51    

:) Merci,
Si ça marche comme ça, c'est très bien, maintenant, il faut compléter et finir par faire TOUT ce que tu souhaite faire,
Je parlais plutôt de ça en fait, n'hésite pas à nous donner des nouvelles de l'avancement de ton projet, enfin, si t'as le temps/envie.
 
Pour ton code, j'ai deux petites remarque:
-C'est un choix délibéré de faire ça en deux lignes? :

Code :
  1. sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM ENTREPRISES WHERE (((ENTREPRISE.NomCourt)="
  2. sRequete = sRequete & Chr$(34) & nomFond & Chr$(34) & " ))"


Tu peux le faire en une seule fois:
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM ENTREPRISES WHERE (((ENTREPRISE.NomCourt)=" & Chr$(34) & nomFond & Chr$(34) & " ))"
Si c'est trop long et que tu souhaite casser la ligne en plusieurs lignes pour mieux la lire:
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM _
 ENTREPRISES WHERE (((ENTREPRISE.NomCourt)=" & Chr$(34) & nomFond & Chr$(34) & " ))"
C'est de la cosmétique, perso, je préfère tout mettre sur une seule ligne :o
 
Le Chr$(34) est judicieux, perso, je prefère la méthode compliquée :o. En gros, pour mettre " dans une chaine de caractères, il suffit de le doubler:
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM ENTREPRISES WHERE (((ENTREPRISE.NomCourt)=""" & nomFond & """ ))"
ça a l'avantage d'être compact, pas bcp plus lisibles, mais plus compact!
Bonne chance pour la suite!

Reply

Marsh Posté le 22-02-2013 à 12:18:51   

Reply

Marsh Posté le 22-02-2013 à 16:40:29    


Citation :

Tu peux le faire en une seule fois:  
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM ENTREPRISES WHERE (((ENTREPRISE.NomCourt)=" & Chr$(34) & nomFond & Chr$(34) & " ))"  
Si c'est trop long et que tu souhaite casser la ligne en plusieurs lignes pour mieux la lire:  
sRequete = "SELECT ENTREPRISE.NomCourt, ENTREPRISE.DateCreation FROM _  
 ENTREPRISES WHERE (((ENTREPRISE.NomCourt)=" & Chr$(34) & nomFond & Chr$(34) & " ))"  
C'est de la cosmétique, perso, je préfère tout mettre sur une seule ligne :o


C'est vrai. J'ai modifié pour la cosmétique.
 
 
Bon, j'ai un peu l'impression d'abuser et d'être vraiment nul, mais comment est ce que je peux faire maintenant pour renvoyer les résultats d'une requête ou il y a plusieurs éléments en réponse ?  
 
Typiquement, afficher toutes les entreprises qui ont été créé en 2002 ?
 
Comme ça, ça permettra de boucler le sujet en ayant vu le cas unique et le cas multiple.
 
Il y a juste la boucle à modifier et le type de variable de retour de la fonction j'imagine ?

Reply

Marsh Posté le 22-02-2013 à 17:08:48    

La boucle à priori est bonne.
Ce que tu dois faire maintenant, c'est programmer la récupération de ces résultats multiples et les afficher.
 
Do Until rstNomSociete.EOF  
    nomfonction = rstNomSociete![NomChampsquivabien]  
    rstNomSociete.MoveNext  
Loop  
 
Le code va boucler (ie repasser dans la boucle) tant qu'il y a d'autres résultats.
Si tu prend ce code inchangée, tu vas les écraser et ne gardera que la dernière.
 
Il y a plusieurs façons de faire mais voici la plus simple:
 
Au lieu de faire une fonction, faire plutôt une procédure sub,
Disons que tu as n résultats, que tu souhaite écrire les uns à la suite des autres dans un tableau démarrant en cellule A1 de ta feuille,
Tu peux alors faire:
i = 1
Do Until rstNomSociete.EOF  
    worksheets("NomFeuille" ).cells(i,1).value = rstNomSociete![NomChampsquivabien1]
    worksheets("NomFeuille" ).cells(i,2).value = rstNomSociete![NomChampsquivabien2]
    worksheets("NomFeuille" ).cells(i,3).value = rstNomSociete![NomChampsquivabien3]
    rstNomSociete.MoveNext  
    i=i+1
Loop  
 
A toi de nettoyer proprement tes plages de données avant l'execution de ta macro et d'être sûr de n'avoir rien en dessous du tableau résultat suscéptible de se faire écraser par un trop grand nombre de résultats
Ce code va executer n fois la boucle (car il trouve n société crées en 2002) et écrire donc n lignes à partir de la ligne 1 sur 3 colonnes (ici A, B et C)
Tu pourra créer un bouton sur ta feuille pour appeler la macro et utiliser les cellules de cette feuille pour entrer ton ou tes critères de recherche.
 
 
Pour le cas unique, la fonction se prête bien à l'exercice, sauf que pour le moment, elle ne renvoi qu'un résultat (la date de création). Il se peut que tu ai envie d'en récupérer plus, même s'il n'y a qu'une seule réponse.
Exemple: tu recherche les données de l'entreprise sncf, il n'y en a qu'une (de sociétés sncf) mais tu veux récupérer 3 ou 4 informations. Il va falloir adapter ta fonction.
Aussi, cette fonction sera exécutée à chaque calcul de la feuille. SI tu es en calcul automatique, c'est un peu la merde: connections sql dans tous les sens, pas optimal en termes de perfs...
Bref, je te conseil de rester plutôt sur les sub, qui se contrôlent mieux!
 
Et n'oublie pas de fermer les rst et les db dans ton code (cf premier exemple avec les instructions .close)

Reply

Marsh Posté le 22-02-2013 à 17:50:12    

Mais pourquoi un truc du genre ne pourrait pas fonctionner ?
J'essaye de créer un tableau dynamique et à chaque boucle je donne la valeur trouvée à la cellule du tableau. Mais bon, ça ne semble pas vouloir fonctionner.
 

Code :
  1. Dim i As Integer
  2. i = 1
  3. Dim EntrepriseDansFond() As String
  4. ReDim EntrepriseDansFond(1)
  5. Do Until rstNomFond.EOF
  6.     EntrepriseDansFond(i) = rstNomFond![Nom]
  7.     rstNomFond.MoveNext
  8.     i = i + 1
  9.     ReDim EntrepriseDansFond(i)
  10. Loop

Reply

Marsh Posté le 22-02-2013 à 17:53:23    

Code :
  1.     ReDim Preserve EntrepriseDansFond(i)


           Voir l'aide de ReDim …
 

Reply

Marsh Posté le 22-02-2013 à 18:09:50    

Ah bah oui forcément  ...
A jouer à l'apprenti sorcier, on peut pas avoir tout bon au premier coup.
 
Ok, donc là ça fonctionne. C'est super. Merci beaucoup.
 
Bon weekend ! Je reviendrai dessus lundi.

Reply

Marsh Posté le 22-02-2013 à 20:34:10    

le petit bleu a écrit :

Ah bah oui forcément  ...
A jouer à l'apprenti sorcier, on


apprends un tas de trucs :)
Bon week end à vous deux
Edit: F1 est d'une grande aide, surtout en 2003, ça marche en 2010 mais moins bien je trouve...

Message cité 1 fois
Message édité par hush hush le 22-02-2013 à 20:35:21
Reply

Marsh Posté le 24-02-2013 à 11:26:03    

hush hush a écrit :

[…] ça marche en 2010 mais moins bien je trouve...

            Idem en 2007 …
 

Reply

Marsh Posté le 25-02-2013 à 13:09:36    

Bon, Back to business.
 
Bonjour, bon lundi à tous.
 
Tout ça, ça marche bien. Maintenant, je cherche à éliminer les doublons de mon tableau obtenu.
 
Je suis entrain de faire un truc assez grossier ou je créé un nouveau tableau que j'alimente depuis le tableau contenant les doublons si la valeur n'est pas déjà dans ce tableau.
 
Donc à chaque fois ça doit parcourir tout le tableau pour vérifier à chaque fois que la valeur n'est pas déjà présente.
Il n'y a rien qui serait plus "fonctionnel" ?
 
En vous remerciant d'avance.


Message édité par le petit bleu le 25-02-2013 à 13:10:16
Reply

Marsh Posté le 25-02-2013 à 13:32:02    

 
           Voir l'aide de la méthode  Find  et l'exemple dans le sujet Macro pour supprimer une ligne
 

Reply

Marsh Posté le 25-02-2013 à 15:40:17    

Comment ça se fait que tu ai des doublons dans ta base? Je pensais que tu avais une seule entrée pour chaque société...
Je creuserais plutôt du coté d'acces pour la "gestion" de données!
Regarde un peu ça: http://www.w3schools.com/sql/sql_distinct.asp
 
Access est vraiment orienté gestion de données, c'est son boulot, il vaut mieux le lui faire faire plutôt que le mimer sur excel,
Excel, c'est bien pour les calculs et une interface utilisateur sympathique.

Reply

Marsh Posté le 25-02-2013 à 16:08:57    

Hé hé !
 

Citation :

Regarde un peu ça: http://www.w3schools.com/sql/sql_distinct.asp


C'est moi qui ne sais pas chercher sur google ou quoi ?
J'ai cherché à le faire avec le mot clé "distinct" mais je n'avais pas trouvé d'exemple clair.
Bref, ça marche super avec ton exemple. Je ne sais pas pourquoi ça n'a pas marché plus tôt ...
 
Cela m'a aussi permis de le faire en VBA également. Mais bon, c'était forcément un peu plus lent.
 

Citation :

Comment ça se fait que tu ai des doublons dans ta base?


En fait c'est le résultat d'une requête qui me renvoi des doublons dans la liste des sociétés. Et je cherchais en effet à supprimer tout ces doublons mais je n'y étais pas arrivé.
En gros, exactement le même cas que dans le lien que tu m'as envoyé.
 
Merci encore !

Reply

Marsh Posté le 25-02-2013 à 16:16:35    

Derien! :)
Pour tes recherches google, je te conseille d'ajouter VBA SQL voir Access en mots clés de tes recherches!
Il y a un nombre incalculables de sites répondants à ces questions courantes :)
Et souvent, tu as une réponse complète et "propre"

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed