Soustraction sous VBA d'une base importante

yanounou -  
 yanounou -
Bonjour,

Je souhaiterais faire une soustraction d'une colonne D - colonne E et afficher le resultat sur la F. Et ce, tant qu'il y a des nombres sur la colonne D ou E.

Vous m'avez déjà aidé pour trouver le code que je vais saisir ci-dessous et je vous en remercie.

En revanche, j'ai remarqué que sur un fichier de plusieurs dizaines de milliers de lignes, la macro prenait 5 à 10 minutes. Ce qui m'étonne car via excel la soustraction est quasiment instantanée.

Sachant que je dois utiliser VBA, auriez vous une idée pour modifier le code pour que ca prenne moins de temps. au pire 30 secondes à 1 munute, mais au delà cela n'est plus efficace.

En vous remerciant par avance

Dim lg, i As Long
With ActiveSheet.Range("D1:E65000")
lg = .Row + .Rows.Count - 1
End With
For i = lg To 2 Step -1
If Cells(i, "D") <> "" And Cells(i, "E") <> "" Then
Cells(i, "F").FormulaR1C1 = "=RC[-2]-RC[-1]"
End If
Next i

Excel 2003

6 réponses

  1. eriiic Messages postés 24581 Date d'inscription   Statut Contributeur Dernière intervention   7 281
     
    Bonjour,

    Ca sert à quoi de poser la question si tu ne testes pas toutes les réponses ?
    Voir ici :
    https://forums.commentcamarche.net/forum/affich-26873406-appliquer-une-formule-jusqu-a-la-derniere-ligne-des-variables#10
    Ce n'est pas parce qu'il n'y a pas de boucle et une seule ligne que c''est incomplet. C'est juste plus rapide parce qu'il n'y a pas de boucle justement.
    Rien à rajouter, éventuellement
    Application.screenupdating=false devant et
    Application.screenupdating=true après.

    eric
    Jamais tu ne répondras à un mp non sollicité...
    Bon, ça c'est fait.
    0
  2. yanounou
     
    Bonsoir,

    Désolé Eric. Il est vrai que comme la formule fonctionnait je n'ai pas testé la votre. Mais quand j'ai voulu la testé sur une base plus grande cela n'alalit plus (lenteur).

    Voici un code où j'ai utilisé votre code. Et cela marche malgré une longueur mais qui ne vient pas de votre code mais des remplacement des "." par des ",".

    En revanche je ne sais plus pourquoi dorénavant le tableau croisé dynamique ne veut plus fonctionner. Pour information en plus de vouloir faire une soustraction dans cette base, je l'utilise par la suite pour créer un VBA.

    Columns("D:E").Select
    Selection.Replace What:=".", Replacement:=",", LookAt:=xlPart, _
    SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
    ReplaceFormat:=False
    Columns("F:F").Select
    Selection.Insert Shift:=xlToRight
    Range("F1").Select
    ActiveCell.FormulaR1C1 = "Montant solde"
    [F2].Resize(Application.Min(Cells(Rows.Count, "D").End(xlUp).Row - 1, Cells(Rows.Count, "E").End(xlUp).Row - 1), 1).FormulaLocal = "=D2-E2"
    Range("A1:R65000").Select
    ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
    "A1:R65000").CreatePivotTable TableDestination:="", TableName:= _
    "Tableau croisé dynamique1", DefaultVersion:=xlPivotTableVersion10
    ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(3, 1)
    ActiveSheet.PivotTables("Tableau croisé dynamique1").AddFields RowFields:= _
    Array("CGR A", "Poste", "Libellé réduit du compte", "Libellé", "Libellé écriture", _
    "Date Compt", "Pièce", "Ets")
    With ActiveSheet.PivotTables("Tableau croisé dynamique1").PivotFields( _
    "Montant solde")
    .Orientation = xlDataField
    .NumberFormat = "# ##0"
    End With

    sauriez vous pourquoi à la premiere etape du TCD (ADD Field), VBA plante ?

    En vous remerciant pour votre aide.
    0
    1. yanounou
       
      Ce qui est etrange c'est que qd ma base fait 2000 lignes, tout marche et rapidement. 15 000 ligne, tout fonctionne mais en revanche les soustractions ou alors le remplacement des points en virgule sont lognues.et quand la base en fait 50 000 (c'est important mais cela peut arriver) et bien là les soustractions et le remplacement des points est tres tres long et le TCD lui est mis en echec au moment du Addfiels.
      0
    2. eriiic Messages postés 24581 Date d'inscription   Statut Contributeur Dernière intervention   7 281
       
      Tu n'as pas ajouté application.screenupdating = false au début du code, ça accélèrera sans doute le remplacement.
      Pour ton TCD je ne sais pas non.
      Peut-être un problème de mémoire, refais un test après un reboot.

      eric
      0
    3. yanounou
       
      Tres bien je vais essayer cela demain car les fichiers sont au boulot. C'est embetant cette histoire de mémoire, une action qui marche sur excel peut bloquer sur VBA a cause de la mémoire ? Après il est vrai que le PC du boulot n'est pas top. Comment on peut résoudre cela ?
      0
    4. eriiic Messages postés 24581 Date d'inscription   Statut Contributeur Dernière intervention   7 281
       
      Si ta macro marche sur un petit fichier et plus sur un grand alors que manuellement ça passe j'ai du mal à imaginer autre chose mais il y a peut-être une autre explication.
      Pas assez de ram tu passes sur la mémoire virtuelle (ça ralenti...) et si pas assez de mémoire virtuelle (à contrôler) ça plante (?)
      0
    5. yanounou
       
      En tout cas tu m'as deja trouvé une bonne partie de la solution. Je vais tester demain l'instruction que tu as indiqué pour voir si ca améliore la performance. Peut etre que quelqu'un en lisant le forum aura une idée d'où ca peut venir.
      0
  3. yanounou
     
    Eric, j'ai placé l'application.screenupdating. Je pense que c'est peut etre un peu mieux mais ca reste tout de meme tres tres tres long. D'après toi le code que je place ne contient pas d'erreur ?

    Sinon j'ai toujours l'erreur dès l'instruction add.fields row field ... je te place le code ci-dessous.

    Sub CMCGR()
    '
    ' CMCGR Macro
    ' Macro enregistrée le 10/01/2013 par b276573
    '

    '
    Application.ScreenUpdating = False
    Columns("D:E").Select
    Selection.Replace What:=".", Replacement:=",", LookAt:=xlPart, _
    SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
    ReplaceFormat:=False
    Columns("F:F").Select
    Selection.Insert Shift:=xlToRight
    Range("F1").Select
    ActiveCell.FormulaR1C1 = "Montant solde"
    Dim lg, i As Long
    With ActiveSheet.Range("D1:E65000")
    lg = .Row + .Rows.Count - 1
    End With
    For i = lg To 2 Step -1
    If Cells(i, "D") <> "" And Cells(i, "E") <> "" Then
    Cells(i, "F").FormulaR1C1 = "=RC[-2]-RC[-1]"
    End If
    Next i
    Application.ScreenUpdating = True
    Range("A1:R65000").Select
    Application.CutCopyMode = False
    ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
    "A1:R65000").CreatePivotTable TableDestination:="", TableName:= _
    "Tableau croisé dynamique1", DefaultVersion:=xlPivotTableVersion10
    ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(3, 1)
    ActiveSheet.Cells(3, 1).Select
    ActiveSheet.PivotTables("Tableau croisé dynamique1").AddFields RowFields:= _
    Array("CGR A", "Poste", "Libellé réduit du compte", "Libellé", "Libellé écriture", _
    "Date Compt", "Pièce", "Ets")
    With ActiveSheet.PivotTables("Tableau croisé dynamique1").PivotFields( _
    "Montant solde")
    .Orientation = xlDataField
    .NumberFormat = "# ##0"

    Cordialement
    0
  4. michel_m Messages postés 18903 Date d'inscription   Statut Contributeur Dernière intervention   3 320
     
    bonjour

    Voici pour la partie longue à tester
    Le code tcd n'aura pas d'influence sur la durée par rapport à un autre code à part la ligne Range ("A1:R65000") qui aurait méritée d'^tre réduite à la dernière ligne utilisée (cf variable derlig) si tu veux gagner du temps

    Sub soustraire() 
    Dim Derlig As Long, T_in(), T_out(), cptr As Long 
    Dim Start As Single 
    
    Start = Timer 
    Application.ScreenUpdating = False 
    Derlig = Cells.Find("*", , , , , xlPrevious).Row 
    T_in = Application.Transpose(Range("D2:E" & Derlig).Value) 
    T_out = Application.Transpose(Range("F2:F" & Derlig).Value) 
    
    For cptr = 1 To UBound(T_in) 
         If T_in(cptr, 1) <> "" Then 
              If T_in(cptr, 2) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2) 
    Next 
    
    Range("F2:F" & Derlig) = Application.Transpose(T_out) 
    Application.ScreenUpdating = True 
    MsgBox "durée : " & Timer - Start & " .sec" 
    
    <code>Sub soustraire()  
    Dim Derlig As Long, T_in(), T_out(), cptr As Long  
    Dim Start As Single  
    
    Start = Timer  
    Application.ScreenUpdating = False  
    Derlig = Cells.Find("*", , , , , xlPrevious).Row  
    T_in = Application.Transpose(Range("D2:E" & Derlig).Value)  
    T_out = Application.Transpose(Range("F2:F" & Derlig).Value)  
    
    For cptr = 1 To UBound(T_in)  
         If T_in(cptr, 1) <> "" Then  
              If T_in(cptr, 2) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2)  
    Next  
    
    Range("F2:F" & Derlig) = Application.Transpose(T_out)  
    Application.ScreenUpdating = True  
    MsgBox "durée : " & Timer - Start & " .sec"  
    End If


    Sans ton classeur je n'ai pu tester la macro

    Excuses moi, Eric, je n'avais pas vu qu'il y avait déjà des réponses !!! :-/

    Michel
    0
    1. eriiic Messages postés 24581 Date d'inscription   Statut Contributeur Dernière intervention   7 281
       
      Pas de mal michel ;-)
      bonne soirée
      0
    2. yanounou
       
      Bonsoir michel,

      Ce code me donnera quelle réponse ? excuse moi je suis novice en VBA. y'a aps de tcd ou de soustraction dans ce code ?
      0
    3. yanounou
       
      A partir de quel moment je dois placer ce code ? (je le ferai demain car les fichiers sont au boulot)
      0
    4. yanounou
       
      merci Michel cela améliore considérablement la vitesse (pour les grosses bases). En revanche,le tcd plante tjrs dès l'étape du addfields. j'ai essayé de le faire chez moi et là tout fonctionne. Donc cela doit être une histoire de ressources insuffisante sur le pc entreprise ?

      En revanche ta macro ne marche pas sur excel 2007 (version que j'aie à la maison) donc j'ai du retenter avec la version d'Éric. tout fonctionne (malgré la version 2007) ça a mis 2 heures mais cela a fonctionné pour la soustraction et pour le tcd ensuite (incroyable).

      Pour tester et confirmer que c'est un probleme de ressources au boulot, pourrais tu me dire quoi changer ds ton code pr que la soustraction fonctionne meme sur vba 2007 ?

      Cordialement
      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. michel_m Messages postés 18903 Date d'inscription   Statut Contributeur Dernière intervention   3 320
     
    Bonjour

    Je t'ai écris que ..."Sans ton classeur je n'ai pu tester la macro "... j'ai aussi 2007

    Donc un extrait 3000 ou 4000 lignes de ton classeur serait le bienvenu

    J'ai proposé la partie "chronophage" et non la partie TCD, cette dernière une fois réduit la surface par la recherche de la dernière ligne, n'avait que peu d'incidence sur la rapidité de la procédure

    pour joindre une pièce
    mettre le classeur sans données confidentielles en pièce jointe sur
    https://www.cjoint.com/
    puis copier l'adresse du lien et la coller dans le message de réponse

    0
    1. yanounou
       
      Ca y est michel, j'ai placé un code et le fichier ds la discussion c-dessous. Je remarque que j'avais pas vu que tu demandais 3000 lignes. Cela est il genant pr ton test de la soustraction si je n'ai mis que qques ligne ? De toute facon je le retesterai tout de suite apres sur une base bien plus grande. Mais là qd je lance le code j'ai l'impression que ce n'est meme pas le nombre de ligne qui le gene, mais le code en lui meme.

      En te remerciant
      0
    2. michel_m Messages postés 18903 Date d'inscription   Statut Contributeur Dernière intervention   3 320
       
      Tu as écris:
      Pour information, la macro (malgré la longueur) est allée au bout avec une base de 16 000 lignes
      pour augmenter la rapidité d'une procédure CE QUI EST TA DEMANDE, et sans connaitre VBA ,il est évident que sur 14 lignes on testera rien du tout

      La partie de la macro pour soustraire - testée avec succès sur 2007
      Dim Derlig As Long, T_in(), T_out(), cptr As Long  
      
      Application.ScreenUpdating = False  
      Derlig = Columns("A").Find("*", , , , , xlPrevious).Row 'dernière ligne avec des données  
      T_in = Range("D2:E" & Derlig).Value  
      Columns("F").Insert  
      Range("F1") = "Libellé écriture"  
      T_out = Application.Transpose(Range("F2:F" & Derlig).Value)  
      
      For cptr = 1 To UBound(T_in)  
           If T_in(cptr, 1) <> "" Then  
                If T_in(cptr, 2) <> "" Then T_out(cptr) = Replace(T_in(cptr, 1), ".", ",") - Replace(T_in(cptr, 2), ".", ",")  
           End If  
      Next  
      
      With Range("F2:F" & Derlig)  
           .Value = Application.Transpose(T_out)  
           .NumberFormat = "##0.00"  
      End With  
      


      mais;
      je me demande l'utilité des tests que tu indiquais au départ
      If Cells(i, "D") <> "" And Cells(i, "E") <> ""
      puisqu'il y a des données dans tes 14 lignes

      d'autre part n'oublie pas de réduire la surface requise pour ton TCD (déjà signalé sans aucune réaction de ta part), car tu risques de ramer et de saturer la RAM et/ou la mémoire virtuelle de ton disque dur:
      Range ("A1:R65000") à remplacer par
      Range ("A1:R" & derlig")
      0
    3. yanounou
       
      en fait le test If cells, il me semble, etait présent pour dire à la macro de faire la soustraction sur toute la colonne (hors en tete) mais jusqu'à la derniere ligne. Car la premiere macro que je m'etais fait faisait que des soustractions étaient calculées meme apres la base et donc donnait une liste de 0 sur toute la colonne. Je vais aussi remplacer le champ range. et voici un nouceau lien avec un fichier d'environ 3800 lignes : http://cjoint.com/13jv/CAtq2GEVLQq.htm

      Aussi, j'ai voulu ajouter le terme : Range("A1:R" & derlig").Select dans le code ci dessous mais du coup VBA dit qu'il ne reconnait plus l'objet global.

      Voici le code :

      Application.ScreenUpdating = False
      Columns("D:E").Select
      Selection.Replace What:=".", Replacement:=",", LookAt:=xlPart, _
      SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
      ReplaceFormat:=False
      Columns("F:F").Select
      Selection.Insert Shift:=xlToRight
      Range("F1").Select
      ActiveCell.FormulaR1C1 = "Montant solde"
      Dim Derlig As Long, T_in(), T_out(), cptr As Long
      Derlig = Cells.Find("*", , , , , xlPrevious).Row
      T_in = Application.Transpose(Range("D2:E" & Derlig).Value)
      T_out = Application.Transpose(Range("F2:F" & Derlig).Value)

      For cptr = 1 To UBound(T_in)
      If T_in(cptr, 1) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2)
      If T_in(cptr, 2) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2)

      Range("F2:F" & Derlig) = Application.Transpose(T_out)
      Next cptr
      Application.ScreenUpdating = True
      Range("A1:R" & "derlig").Select
      Application.CutCopyMode = False
      ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
      "A1:R" & "derlig").CreatePivotTable TableDestination:="", TableName:= _
      "Tableau croisé dynamique1", DefaultVersion:=xlPivotTableVersion10
      ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(3, 1)
      ActiveSheet.Cells(3, 1).Select
      ActiveSheet.PivotTables("Tableau croisé dynamique1").AddFields RowFields:= _
      Array("CGR A", "Poste", "Libellé réduit du compte", "Libellé", "Libellé écriture", _
      "Date Compt", "Pièce", "Ets")
      With ActiveSheet.PivotTables("Tableau croisé dynamique1").PivotFields( _
      "Montant solde")
      .Orientation = xlDataField
      .NumberFormat = "#,##0"
      End With
      0
    4. michel_m Messages postés 18903 Date d'inscription   Statut Contributeur Dernière intervention   3 320
       
      P....!
      JE PASSE DU TEMPS POUR TE DONNER UN CODE ET TU TE BORNES A RECOPIER TES ANERIES

      ALORS DEM... TOI TOUT SEUL
      0
    5. yanounou
       
      J'essaie de recopier le code comme toi et eric me l'ont corrigé. ici j'ai ajouté A1:R" & "derlig comme tu me l'a dit juste avant. à moins que j'ai mal compris. Désolé pour le derangement. Mais sache que je ne suis pas du tout informaticien de formation.
      0
  7. yanounou
     
    Bonjour Eric et Michel en cette journée enneignée,

    Voici le lien pour un fichier exemple ( j'ai pris une base très limitée en ligne) : http://cjoint.com/?CAtmzYZLSLI

    et voici le code que j'utilise actuellement sur vba 2007 et qui plante au niveau de la soustraction (à savoir que sur vba 2003 cela fonctionnait) :

    Application.ScreenUpdating = False
    Columns("D:E").Select
    Selection.Replace What:=".", Replacement:=",", LookAt:=xlPart, _
    SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
    ReplaceFormat:=False
    Columns("F:F").Select
    Selection.Insert Shift:=xlToRight
    Range("F1").Select
    ActiveCell.FormulaR1C1 = "Montant solde"
    Dim Derlig As Long, T_in(), T_out(), cptr As Long
    Derlig = Cells.Find("*", , , , , xlPrevious).Row
    T_in = Application.Transpose(Range("D2:E" & Derlig).Value)
    T_out = Application.Transpose(Range("F2:F" & Derlig).Value)

    For cptr = 1 To UBound(T_in)
    If T_in(cptr, 1) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2)
    If T_in(cptr, 2) <> "" Then T_out(cptr) = T_in(cptr, 1) - T_in(cptr, 2)
    End If
    Range("F2:F" & Derlig) = Application.Transpose(T_out)
    Next cptr
    Application.ScreenUpdating = True
    Range("A1:R65000").Select
    Application.CutCopyMode = False
    ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
    "A1:R65000").CreatePivotTable TableDestination:="", TableName:= _
    "Tableau croisé dynamique1", DefaultVersion:=xlPivotTableVersion10
    ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(3, 1)
    ActiveSheet.Cells(3, 1).Select
    ActiveSheet.PivotTables("Tableau croisé dynamique1").AddFields RowFields:= _
    Array("CGR A", "Poste", "Libellé réduit du compte", "Libellé", "Libellé écriture", _
    "Date Compt", "Pièce", "Ets")
    With ActiveSheet.PivotTables("Tableau croisé dynamique1").PivotFields( _
    "Montant solde")
    .Orientation = xlDataField
    .NumberFormat = "#,##0"
    End With

    Cordialement
    0