Fichier centralisateur de plusieurs fichiers
Bonjour,
Je cherche à écrire une procédure à partir du fichier centralisateur (Destination) pour importer par copier-coller les données se trouvant sur plusieurs fichiers Source.
Les fichiers Destination et Sources ont la même structure.
Ma logique:
Pour chaque fichier Source,
Pour chaque ligne de Source,
Si Cellule date renseignée, alors
Pour chaque ligne de Destination,
Si Code Destination = Code Source, alors
Copier cellules Source
Coller dans cellules Destination
Ligne Destination suivante
Ligne Source suivante
Fichier Source suivant.
La procédure suivante (partie en italique de "Ma logique") fonctionne correctement avec un seul fichier Source:
'en ayant ouvert les fichiers Sources
Sub MiseAjour()
Dim wDest As Workbook 'déclare le fichier de Destination
Dim fDest As Worksheet 'déclare la feuille du fichier de Destination
Dim lgDe As Integer 'déclare le nombre de lignes du fichier Destination
Dim wOrig As Workbook 'déclare le fichier Source
Dim fOrig As Worksheet 'déclare la feuille du fichier Source
Dim lgOr As Integer 'déclare le nombre de ligne du fichier Source
Application.ScreenUpdating = False 'désactive le rafraichissement de l'écran, accélère la procédure
Set wDest = Workbooks("AAAAA.xlsm") 'définit le fichier de Destination AAAAA
Set fDest = Workbooks("AAAAA.xlsm").Sheets("Base") 'définit la feuille "Base" du fichier de Destination AAAAA
Set wOrig = Workbooks("AAAAA01.xlsm") 'définit le fichier Source AAAAA01
Set fOrig = Workbooks("AAAAA01.xlsm").Sheets("Base") 'définit la feuille "Base" du fichier Source AAAAA01
For lgOr = 4 To fOrig.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Source
If fOrig.Range("L" & lgOr) <> "" Then 'Si date réalisée renseignée
For lgDe = 4 To fDest.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Destination
If Range("A" & lgDe) = fOrig.Range("A" & lgOr) Then 'Si N°Code en Destination = N°Code en Source, alors
Range("L" & lgOr).Copy 'Copier la cellule Source
fDest.Range("L" & lgDe).PasteSpecial xlPasteValues 'Coller valeur dans cellule Destination
fDest.Range("L" & lgDe).PasteSpecial xlPasteFormats 'Coller format dans cellule Destination
Range("AE" & lgOr & ":AU" & lgOr).Copy 'Copier la plage Source
fDest.Range("AE" & lgDe).PasteSpecial xlPasteValues 'Coller valeur de la plage à partir de la 1ère cellule Destination
fDest.Range("AE" & lgDe).PasteSpecial xlPasteFormats 'Coller valeur de la plage à partir de la 1ère cellule Destination
End If
Next lgDe 'à la prochaine ligne de Destination
End If
Next lgOr 'à la prochaine ligne de Source
Application.ScreenUpdating = True 'réactive le rafraichissement de l'écran
End SubMa question : comment boucler pour appeler tous les fichiers Source AAAAA01 à AAAAA20 situés dans un même dossier ?
Merci pour votre aide,
Cordialement
Bonjour,
une proposition d'adaptation (non testée). Suppose que tous les fichiers à triater soient ouverts dans la même instance d' excel avant exécution de la macro.
'en ayant ouvert les fichiers Sources
Sub MiseAjour()
Dim wDest As Workbook 'déclare le fichier de Destination
Dim fDest As Worksheet 'déclare la feuille du fichier de Destination
Dim lgDe As Long 'déclare le nombre de lignes du fichier Destination
Dim wOrig As Workbook 'déclare le fichier Source
Dim fOrig As Worksheet 'déclare la feuille du fichier Source
Dim lgOr As Long 'déclare le nombre de ligne du fichier Source
Dim nf As Long 'numéro de fichier à traiter
Application.ScreenUpdating = False 'désactive le rafraichissement de l'écran, accélère la procédure
Set wDest = Workbooks("AAAAA.xlsm") 'définit le fichier de Destination AAAAA
Set fDest = Workbooks("AAAAA.xlsm").Sheets("Base") 'définit la feuille "Base" du fichier de Destination AAAAA
For nf = 1 To 20 'on traite les fichiers 1 à 20
Set wOrig = Workbooks("AAAAA" & Format(nf, "00") & ".xlsm") 'définit le fichier Source AAAAAxx
Set fOrig = wOrig.Sheets("Base") 'définit la feuille "Base" du fichier Source AAAAAxx
For lgOr = 4 To fOrig.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Source
If fOrig.Range("L" & lgOr) <> "" Then 'Si date réalisée renseignée
For lgDe = 4 To fDest.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Destination
If fdest.Range("A" & lgDe) = fOrig.Range("A" & lgOr) Then 'Si N°Code en Destination = N°Code en Source, alors
forig.Range("L" & lgOr).Copy 'Copier la cellule Source
fDest.Range("L" & lgDe).PasteSpecial xlPasteValues 'Coller valeur dans cellule Destination
fDest.Range("L" & lgDe).PasteSpecial xlPasteFormats 'Coller format dans cellule Destination
forig.Range("AE" & lgOr & ":AU" & lgOr).Copy 'Copier la plage Source
fDest.Range("AE" & lgDe).PasteSpecial xlPasteValues 'Coller valeur de la plage à partir de la 1ère cellule Destination
fDest.Range("AE" & lgDe).PasteSpecial xlPasteFormats 'Coller valeur de la plage à partir de la 1ère cellule Destination
End If
Next lgDe 'à la prochaine ligne de Destination
End If
Next lgOr 'à la prochaine ligne de Source
Next nf
Application.ScreenUpdating = True 'réactive le rafraichissement de l'écran
End SubBonsoir H2SO4,
Merci beaucoup pour votre solution que j'ai bien comprise.
La procédure remplit bien le fichier Destination AAAAA, mais en cours d'exécution apparaît le message "Erreur d'exécution 9, L'indice n'appartient pas à la sélection".
En débogant, j'obtiens cette ligne surlignée en jaune :
Set wOrig = Workbooks("AAAAA" & Format(nf, "00") & ".xlsm") 'définit le fichier Source AAAAAxx
J'ai essayé en enregistrant les fichiers par AAAAA1 et AAAAA2 au lieu de AAAAA01 et AAAAA02, et en corrigeant la ligne par :
Set wOrig = Workbooks("AAAAA" & nf & ".xlsm") 'définit le fichier Source AAAAAxxMais le message d'erreur se reproduit.
Qu'en pensez-vous ?
Cordialement,
Désolé H2SO4,
Je faisais mes essais avec seulement 2 fichiers Sources AAAAA01 et AAAAA02, et non 20 comme nécessaire à terme.
J'ai alors fait un essai avec For nf =1 to 2, au lieu de For nf = 1 to 20, et là, ça marche sans message d'erreur !
Merci donc pour cette boucle élégante !
Pour aller plus loin, que faudrait-il ajouter pour réaliser les mêmes opérations mais à partir de fichiers fermés dans un dossier unique AAAAAXX ?
Aller au dossier AAAAAXX des fichiers AAAAA01 à AAAAA20
Pour chaque fichier
Ouvrir le fichier
Exécuter la boucle
Fermer le dossier
Fichier suivant
Merci encore si vous pouviez me mettre sur la voie !
Cordialement
bonsoir,
adaptation du code pour ouvrir fichiers source (adapter le nom du répertoire dans le code ci-dessous). non testé.
'en ayant ouvert les fichiers Sources
Sub MiseAjour()
Dim wDest As Workbook 'déclare le fichier de Destination
Dim fDest As Worksheet 'déclare la feuille du fichier de Destination
Dim lgDe As Long 'déclare le nombre de lignes du fichier Destination
Dim wOrig As Workbook 'déclare le fichier Source
Dim fOrig As Worksheet 'déclare la feuille du fichier Source
Dim lgOr As Long 'déclare le nombre de ligne du fichier Source
Dim nf As Long 'numéro de fichier à traiter
Dim repertoire As String
Dim nomfichier As String
Application.ScreenUpdating = False 'désactive le rafraichissement de l'écran, accélère la procédure
repertoire = "c:\nom du répertoire contenant les fichiers source" ' <--------------------------------------------à adapter
Set wDest = Workbooks("AAAAA.xlsm") 'définit le fichier de Destination AAAAA
Set fDest = Workbooks("AAAAA.xlsm").Sheets("Base") 'définit la feuille "Base" du fichier de Destination AAAAA
For nf = 1 To 20 'on traite les fichiers 1 à 20
nomfichier = repertoire & "\AAAAA" & Format(nf, "00") & ".xlsm" 'définit le fichier Source AAAAAxx
Set wOrig = Workbooks.Open(nomfichier) ' ouverture du classeur
Set fOrig = wOrig.Sheets("Base") 'définit la feuille "Base" du fichier Source AAAAAxx
For lgOr = 4 To fOrig.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Source
If fOrig.Range("L" & lgOr) <> "" Then 'Si date réalisée renseignée
For lgDe = 4 To fDest.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Destination
If fDest.Range("A" & lgDe) = fOrig.Range("A" & lgOr) Then 'Si N°Code en Destination = N°Code en Source, alors
fOrig.Range("L" & lgOr).Copy 'Copier la cellule Source
fDest.Range("L" & lgDe).PasteSpecial xlPasteValues 'Coller valeur dans cellule Destination
fDest.Range("L" & lgDe).PasteSpecial xlPasteFormats 'Coller format dans cellule Destination
fOrig.Range("AE" & lgOr & ":AU" & lgOr).Copy 'Copier la plage Source
fDest.Range("AE" & lgDe).PasteSpecial xlPasteValues 'Coller valeur de la plage à partir de la 1ère cellule Destination
fDest.Range("AE" & lgDe).PasteSpecial xlPasteFormats 'Coller valeur de la plage à partir de la 1ère cellule Destination
'exit for ' si ligne trouvée on peut sortir de la boucle
End If
Next lgDe 'à la prochaine ligne de Destination
End If
Next lgOr 'à la prochaine ligne de Source
wOrig.Close False 'fermeture du classeur
Next nf
Application.ScreenUpdating = True 'réactive le rafraichissement de l'écran
End SubBonjour H2SO4,
Merci beaucoup pour votre aide qui est allée jusqu'à écrire les lignes !
J'apprécie votre pédagogie par l'exemple juste, la logique du code est très claire.
J'ai encore appris sur l'usage des variables, ce qui me gêne encore pour passer de l'idée à la réalisation !
Votre adaptation a parfaitement fonctionné au premier essai.
Je suppose que le Exit for en commentaire était une suggestion. Je l'ai placé en ligne de code et le programme s'est bien déroulé. Je pourrais placer un timer pour tester le gain de temps en conditions réelles sur 2000 lignes.
Encore merci !
Bonne journée
bonjour
Je suppose que le Exit for en commentaire était une suggestion.
En effet.
Si les performances posent problèmes, il est encore possible d'améliorer significativement l'efficacité du code. Si chaque fichier contient environ 2000 lignes et en supposant qu'il n'y ait que 25% de lignes avec une date, la macro devrait lire 20*2000*(2000*50%*25%) lignes soit 10.000.000 de lignes. (20.000.000 sans le exit for). On peut réduire ce nombre à 21*2000 soit 42.000 lignes lues.
Quantification intéressante...
Proposeriez-vous une autre architecture de la procédure ?
bonjour,
une autre architecture de la procédure (utilise l'objet dictionnaire, non disponible sur MAC). non testée
'en ayant ouvert les fichiers Sources
Sub MiseAjour()
Dim wDest As Workbook 'déclare le fichier de Destination
Dim fDest As Worksheet 'déclare la feuille du fichier de Destination
Dim lgDe As Long 'déclare le nombre de lignes du fichier Destination
Dim wOrig As Workbook 'déclare le fichier Source
Dim fOrig As Worksheet 'déclare la feuille du fichier Source
Dim lgOr As Long 'déclare le nombre de ligne du fichier Source
Dim nf As Long 'numéro de fichier à traiter
Dim repertoire As String
Dim nomfichier As String
Dim dict As Object
Set dict = CreateObject("scripting.dictionary") 'on utilise un dictionnaire pour retrouver rapidement le numéro de ligne d'un libellé
Application.ScreenUpdating = False 'désactive le rafraichissement de l'écran, accélère la procédure
For lgDe = 4 To fDest.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Destination
dict(fDest.Range("A" & lgDe).Value) = lgDe 'on associe n° de ligne et libellé du fichier destination
Next lgDe 'à la prochaine ligne de Destination
repertoire = "c:\nom du répertoire contenant les fichiers source" ' <--------------------------------------------à adapter
Set wDest = Workbooks("AAAAA.xlsm") 'définit le fichier de Destination AAAAA
Set fDest = Workbooks("AAAAA.xlsm").Sheets("Base") 'définit la feuille "Base" du fichier de Destination AAAAA
For nf = 1 To 20 'on traite les fichiers 1 à 20
nomfichier = repertoire & "\AAAAA" & Format(nf, "00") & ".xlsm" 'définit le fichier Source AAAAAxx
Set wOrig = Workbooks.Open(nomfichier) ' ouverture du classeur
Set fOrig = wOrig.Sheets("Base") 'définit la feuille "Base" du fichier Source AAAAAxx
For lgOr = 4 To fOrig.Range("A" & Rows.Count).End(xlUp).Row 'Pour chaque ligne du fichier Source
If fOrig.Range("L" & lgOr) <> "" Then 'Si date réalisée renseignée
lgDe = dict(fOrig.Range("A" & lgOr).Value) 'on recherche le n° de ligne associé au libellé de la ligne d'origine
fOrig.Range("L" & lgOr).Copy 'Copier la cellule Source
fDest.Range("L" & lgDe).PasteSpecial xlPasteValues 'Coller valeur dans cellule Destination
fDest.Range("L" & lgDe).PasteSpecial xlPasteFormats 'Coller format dans cellule Destination
fOrig.Range("AE" & lgOr & ":AU" & lgOr).Copy 'Copier la plage Source
fDest.Range("AE" & lgDe).PasteSpecial xlPasteValues 'Coller valeur de la plage à partir de la 1ère cellule Destination
fDest.Range("AE" & lgDe).PasteSpecial xlPasteFormats 'Coller valeur de la plage à partir de la 1ère cellule Destination
End If
Next lgOr 'à la prochaine ligne de Source
wOrig.Close False 'fermeture du classeur
Next nf
Application.ScreenUpdating = True 'réactive le rafraichissement de l'écran
End SubIl est encore possible d'améliorer les performances en évitant au maximum les interactions avec la feuille de calcul excel (instructions de lecture de cellule, de copy, de paste ... qui sont les plus pénalisantes d'un point de vue performances), mais pour ces améliorations, il faut les faire en connaissant la structure et la mise en page du fichier (si la mise en page est importante)
Merci H2SO4,
Vous m'ouvrez de nouvelles pistes d'étude !
Je regarderai votre dernière proposition dans un moment, lorsque je serai moins pris par le chrono !
Merci encore et bonne après-midi.