IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VBA Access Discussion :

Exportation excel trop longue, et MoveNext qui ne fonctionne pas [AC-2003]


Sujet :

VBA Access

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut Exportation excel trop longue, et MoveNext qui ne fonctionne pas
    Bonjour à tous

    Voila deux heures que je suis sur un problème qui ne me parait reposer que sur quelques bases techniques, mais on dirait que je suis bel et bien bloquée... Après avoir essayé, et essayé, ..., différentes méthodes, j'en fais appel à votre aide :


    Je voudrai exporter dans un fichier excel certaines données contenues dans mes tables.
    La table en question comprend un numéro de salarié, une date, et un lieu. Le problème est que chaque salarié apparait dans 6 enregistrements différents (à cause de la date : il me fallait un enregistrement par jour ouvrable de la semaine). Je voudrai afficher sur excel les numéros de salarié, mais n'en afficher qu'un seul pour les six enregistrements.
    (précision : il me faut laisser 2 lignes vides entre chaque numéro de salarié, et commencer à la ligne 2)


    Mon premier code, après moultes bidouillages, a fini par marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
        Dim db As DAO.Database
        Dim rstEmployeLieu As DAO.Recordset
     
        Set db = CurrentDb()
        Set rstEmployeLieu = db.OpenRecordset("T_Association_Employe_Lieu")
     
     
        rstEmployeLieu.MoveFirst
        Dim Nouveau As Boolean
        Dim indice As Integer
        Nouveau = True
        indice = 2
     
        For i = 0 To rstEmployeLieu.RecordCount - 1
            'Pour chaque enregistrement on vérifie si le numéro de salarié est déjà incrit dans le classeur Excel
            'j sert à naviguer de ligne en ligne pour la vérification
            For j = 0 To rstEmployeLieu.RecordCount - 1
                If (xlSheet.Cells((j * 3 + 2), 1) = rstEmployeLieu("NoSalarie")) Then
                    '"nouveau" sert à savoir si le numéro de salarié n'a pas été encore affiché une seule fois
                    'si l'une des cases est égale au numéro de salarié actuel, alors ce n'est pas la première fois, donc on le met à False, et on sort de la boucle
                    Nouveau = False
                    Exit For
                End If
            Next j
     
            'Si au contraire il est nouveau, on l'insert dans la feuille Excel
            If (Nouveau = True) Then
                xlSheet.Cells((indice), 1) = rstEmployeLieu("NoSalarie")
                indice = indice + 3
            End If
     
            rstEmployeLieu.MoveNext
            Nouveau = True
        Next i

    Le problème de cette méthode est qu'elle est montrueusement longue à l'exécution : pas loin d'une minute, et ce n'est que le tout premier calcul de la feuille... =/



    Je me suis donc dit que "sauter" les enregistrements qui font doublon pour le numéro de salarié, bien qu'un peu plus brouillon (puisqu'il faut impérativement les entrer dans l'ordre), serait une méthode beaucoup plus rapide que de vérifier ligne par ligne. J'ai donc écrit ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        rstEmployeLieu.MoveFirst
        Dim indice As Integer
        For i = 0 To rstEmployeLieu.RecordCount - 1
            xlSheet.Cells((i*3+2), 1) = rstEmployeLieu("NoSalarie")
            rstEmployeLieu.MoveNext
            rstEmployeLieu.MoveNext
            rstEmployeLieu.MoveNext
            rstEmployeLieu.MoveNext
            rstEmployeLieu.MoveNext
        Next i
    Là, j'avoue être perplexe : le premier MoveNext fonctionne parfaitement, mais les suivants me disent "aucun enregistrement en cours". Je ne comprends pas la logique : si je n'en mets qu'un, il fera de toute façon un deuxième MoveNext quand il passera à nouveau dans la boucle (et j'ai testé, il n'y a aucun problème dans ce cas), alors pourquoi pas là ? La seule différence est l'incrémentation du i, mais je ne vois pas en quoi ça influe sur mon Recordset...



    Pitié j'implore votre aide.... T_T

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur VBA Access
    Inscrit en
    Avril 2006
    Messages
    1 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur VBA Access

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 109
    Points : 1 535
    Points
    1 535
    Par défaut
    Bonjour,
    si tu souhaites qu'un seul enregistrement par salarié, essaie en triant la recordset sur le NoSalarie et utilise une variable qui reçoit le dernier NoSalarie copié dans le feuillet Excel.


    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
       Dim db As DAO.Database
        Dim rstEmployeLieu As DAO.Recordset
        Dim EmployeNum As String 'doit être du même type que le champ NoSalarie
        Set db = CurrentDb()
        Set rstEmployeLieu = db.OpenRecordset("SELECT * FROM T_Association_Employe_Lieu ORDER BY NoSalarie")
        EmployeNum=""
        indice = 2
     
        With RcdEmployeLieu
           'Lire le recordset jusqu'à ce que la fin (EndOfFile) soit atteinte 
           While Not .EOF 
             'Si le NoSalarie est différent que EmployeNum alors copié
              If EmployeNum<>!NoSalarie Then
                EmployeNum=!NoSalarie
                XlsSheet.Cells(Indice,1)=EmployeNum
                Indice=Indice+3
              End if
              .MoveNext
           Wend
        End With

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    C'est un million de fois plus rapide que ma méthode \o/

    Merci beaucoup

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Bon, euh... il parait que c'est pas drôle si c'est trop simple, alors...

    Toujours le même problème, à un petit détail près : je voudrai cette fois afficher le NOM, du salarié, dans la feuille Excel. Pour ça j'ai une autre table, T_Salarie, qui contient le NoSalarie en clé principale, et un champ "Nom".
    (qu'est-ce qu'on rigole, hein.. )

    (et puis attendez, après j'ai encore plus drôle, vous allez voir (du moins si je bloque encore) *partie se cacher éviter les tirs de tomate* )


    J'ai essayé deux trois petites choses, mais là encore, impossible de voir si elles marchent, Excel étant trop long à répondre =/ (je n'ai jamais appris à optimiser mon code en terme de rapidité... )


    Voilà les deux principaux essais que j'ai effectué :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    'à la suite du code précédent :
     
        Dim rstSalarie As DAO.Recordset
        Dim critereSalarie As String
     
        Set rstSalarie = db.OpenRecordset("T_Salarie", dbOpenDynaset)
        indice = 2
        critereSalarie = "[NoSalarie] = " & xlSheet.Cells(indice, 1)
     
        rstSalarie.FindFirst critereSalarie
        While Not rstSalarie.NoMatch
            xlSheet.Cells(indice, 1) = rstSalarie("Nom")
            indice = indice + 3
            rstSalarie.FindFirst critereSalarie
        Wend


    Ou bien alors, plus compliqué (j'ai essayé de commenter le code au plus clair )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Dim rstSalarie As DAO.Recordset
        Dim critereSalarie As String
        Dim nomEmployeSeek As String
        Dim nomEmployeXL As String
        Dim indice As Integer
     
        rstEmployeLieu.MoveFirst
        Set rstSalarie = db.OpenRecordset("T_Salarie", dbOpenDynaset)
        critereSalarie = "[NoSalarie] = " & rstEmployeLieu("NoSalarie")
        nomEmployeSeek = ""
        nomEmployeXL = ""   'représente les noms contenus dans la feuille Excel
        indice = 2
        rstSalarie.MoveFirst
     
        'On prend les numéros d'employé un à un
        While Not rstEmployeLieu.EOF
            'On prend le nom équivalent
            rstSalarie.FindFirst critereSalarie
            While Not rstSalarie.NoMatch
                'On stocke le nom d'employé trouvé dans la variable "nomEmployeSeek"
                nomEmployeSeek = rstSalarie("Nom")
                'S'il est différent de ceux inscrits dans la feuille Excel, on le stocke et l'inscrit
                If nomEmployeSeek <> nomEmployeXL Then
                    nomEmployeXL = nomEmployeSeek
                    xlSheet.Cells(indice, 1) = nomEmployeXL
                    indice = indice + 3
                End If
            'Il n'existe pas deux numéros de salariés identiques dans la table T_Salarie, on peut sortir de la boucle sans FindNext
            Wend
            rstEmployeLieu.MoveNext
        Wend

    Aucune de ces deux méthodes ne marchent, elles font toutes les deux planter Access... =/

    La première indique Dépassement de capacité, et la deuxième met trop longtemps pour avoir un message d'erreur (ou en tout cas je n'ai pas eu la patience de l'attendre :] )



    .

  5. #5
    Rédacteur/Modérateur

    Avatar de Jean-Philippe André
    Homme Profil pro
    Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Inscrit en
    Juillet 2007
    Messages
    14 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2007
    Messages : 14 629
    Points : 34 334
    Points
    34 334
    Par défaut
    Salut,
    et pourquoi ne cherches-tu pas à utiliser CopyFromRecordset ?
    Cycle de vie d'un bon programme :
    1/ ça fonctionne 2/ ça s'optimise 3/ ça se refactorise

    Pas de question technique par MP, je ne réponds pas

    Mes ouvrages :
    Apprendre à programmer avec Access 2016, Access 2019 et 2021

    Apprendre à programmer avec VBA Excel
    Prise en main de Dynamics 365 Business Central

    Pensez à consulter la FAQ Excel et la FAQ Access

    Derniers tutos
    Excel et les paramètres régionaux
    Les fichiers Excel binaires : xlsb,

    Autres tutos

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Parce que je ne connaissais pas ^^

    Mais un CopyFromRecordset recopierait l'intégralité du Recordset, non ?

    Mais en réalité je crois que ce "dépassement de capacité" venait en fait d'Excel. Je m'explique :

    Dans ma tête, la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    critereSalarie = "[NoSalarie] = " & xlSheet.Cells(indice, 1)
    était dynamique, et donc se modifiait à chaque changement d'indice. En réalité non, et c'est pourquoi mon code faisait écrire à l'infini dans Excel, d'où le dépassement de capacité au bout d'un certain temps.


    J'ai donc actualisé la valeur de "critereSalarie" avant le nouveau FindFirst :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        Dim rstSalarie As DAO.Recordset
        Dim critereSalarie As String
        
        Set rstSalarie = db.OpenRecordset("T_Salarie", dbOpenDynaset)
        indice = 2
        critereSalarie = "[NoSalarie] = " & xlSheet.Cells(indice, 1)
        
        rstSalarie.FindFirst critereSalarie
        While Not rstSalarie.NoMatch
            xlSheet.Cells(indice, 1) = rstSalarie("Nom")
            indice = indice + 3
            critereSalarie = "[NoSalarie] = " & xlSheet.Cells(indice, 1)
            rstSalarie.FindFirst critereSalarie
        Wend

    Mais il me marque "Erreur de syntaxe (opérateur absent) dans l'expression.". Je crois que c'est au niveau du tout dernier enregistrement. Pourquoi ?

    .

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    En essayant ce même code avec différentes copies de mes tables, je me suis aperçue qu'il semblerait qu'il ne fonctionne que lorsqu'il existe un enregistrement de T_Association_Salarie_Lieu pour lequel le NoSalarie n'existe pas .. (ce qui devrait être impossible, il existe une relation Un à Plusieurs entre T_Association_Salarie_Lieu et T_Salarie). Est-ce que quelqu'un pourrait m'expliquer pourquoi, et comment pallier à ce problème ? Est-ce qu'il vient de mon code ? De mes tables ?

    Pourtant, une cellule vide devrait être considérée comme un NoSalarie non existant, non ?


    Edit :

    Je fais finalement les questions réponses (maintenant que je l'ai posée, autant que j'écrive aussi la solution que je viens de trouver...)

    En fait, mon NoSalarie étant un numéro automatique, et une cellule vide étant un String égal à "", les types étaient incompatibles.

    Je vais donc mettre la dernière cellule à 0, que j'écrirai en blanc pour le laisser invisible


    Voila voila, désolée pour le dérangement de ce dernier message...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2007] Export vers Excel 2007 qui ne fonctionne pas
    Par zoom61 dans le forum VBA Access
    Réponses: 2
    Dernier message: 10/09/2014, 11h44
  2. [XL-2007] Formule Excel trop longue
    Par Dady60 dans le forum Excel
    Réponses: 4
    Dernier message: 06/09/2012, 00h03
  3. une requête de suppression qui ne fonctionne pas (trop longue)
    Par clavier12AZQSWX dans le forum Requêtes
    Réponses: 9
    Dernier message: 25/07/2011, 16h03
  4. Réponses: 4
    Dernier message: 15/05/2007, 10h10
  5. export excel trop de données à envoyer
    Par laurent.w dans le forum Access
    Réponses: 9
    Dernier message: 06/02/2007, 21h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo