Extraire des données de deux databases pour les comparer

Bonjour,

J'essaye d'extraire des données de deux databases pour les comparer. Chaque database (.aif) a ses données triées par colonnes avec le nom de la donnée en première ligne son unité en seconde et les valeurs ensuite. Le nombre de valeurs et donc la longueur de la colonne varie d'une database à l'autre, le nom des données et leur position est cependant le même dans chaque database.

Je veux ensuite que la macro copie la colonne correspondant à la donnée recherchée à l'endroit que j'indiquerai manuellement dans la macro.

Au départ, je souhaitais que ma macro recherche les données à partir des noms dans les têtes de colonnes en rouge de mon tableur. J'ai abandonné l'idée car pour l'instant je préfère rentrer directement le nom de la donnée dans la macro, je modifierai plus tard.

Je pense que ma macro a un problème à partir de la ligne 12. Je n'en suis pas certain pour autant.

Sub Test()
    Dim principal As ThisWorkbook
    Dim repertoire As String, fichier$
    Application.ScreenUpdating = False
    Set principal = ThisWorkbook
    repertoire = "G:\01_Projets en cours\2016_Mode 2.2\Données générales\" 'répertoire où aller chercher les fichiers
    fichier = Dir(repertoire & "*.aif") 'choisir le type d'extension du fichier à extraire
    Do While fichier <> ""
        Workbooks.Open (repertoire & fichier)
        Dim i As Long
        For i = 1 To Range("a" & Columns.Count).End(xlUp).Columns 'Permet de sélectionner et copier/coller la colonne désirée
            If Range("a" & i) Like "*Table1*" Then Columns(i).Select
            Selection.Copy Destination:=principal.Sheets(1).Range("G2").End(xlUp) '.Range("a" & Columns.Count).End(xlUp).Offset(1)
            ActiveWorkbook.Close
            fichier = Dir
        Next i
    Loop
End Sub

Si possible, je souhaiterai d'abord des indications pour arriver à faire le maximum moi même, ça me servira par la suite

Merci d'avance pour votre aide!

20comparaison.xlsm (21.14 Ko)

Bonjour,

J'ai tenté une réécriture corrective (mastics lignes/colonnes) mais au bout de compte trop d'éléments indécis pour que je la lâche !

Récapitulons :

Tu vas chercher deux bases pour les comparer : 2 confirmé ? pas plus ?

Après ouverture du classeur, tu détermines le nombre de colonnes (la dernière sur la ligne 1) : déduction (car cela fait partie des mastics...) à confirmer !

Tu parcours les colonnes pour récupérer celles qui contiennent Table1 en ligne 1 : également à confirmer !

Tu les affectes sur ta feuille cible, la 1re en col. G, la 2e en col. I, la 3e en col. K, etc. : encore à confirmer !

Pour le second classeur, la même affectation se fera alors en H, J, L, etc. : toujours à confirmer !

Là il nous faut des variables supplémentaires... i représente la colonne source, il n'est pas dit que toutes les colonnes contiennent Table1 (sinon pourquoi tester !), il faut donc gérer l'affectation avec d'autres variables...

En attendant, ces confirmations (ou non) autres remarques sur le code :

  • les déclarations de variables se placent toutes et toujours en tête de procédure, avant la 1re ligne de code exécutable
  • ThisWorkbook est une propriété que VBA met à ta disposition et qui à tout moment ne peut désigner qu'un objet et un seul ! Vouloir le reprendre dans une autre variable n'est pas très cohérent, et du temps perdu, tant qu'à affecter un objet, autant le faire pour la feuille cible.
  • Toutes les expressions méritent d'être qualifiées par les objets auxquels elle réfèrent (Classeur, Feuille, etc.) et non seulement un échantillon, on y gagne en fiabilité et rapidité
  • Dans la boucle i il ne doit évidemment pas y avoir d'instruction concernant le classeur, telle que Close (là ta boucle serait courte, on ne transfère qu'une colonne et on ferme !)
A moins que ce ne soit le but et que Table1 ne peut figurer que dans une colonne... ! Mais dans ce cas tu n'aurais que 2 colonnes au total, donc cela semble incohérent... Mais tu vaas préciser tout ça.

Cordialement.

Bonjour!

Merci de ton aide! mes réponses ci dessous en rouge.

Récapitulons :

Tu vas chercher deux bases pour les comparer : 2 confirmé ? pas plus ? Oui, seulement deux

Après ouverture du classeur, tu détermines le nombre de colonnes (la dernière sur la ligne 1) : déduction (car cela fait partie des mastics...) à confirmer ! Je suppose que tu parles de la ligne "For i = 1 To Range("a" & Columns.Count)...", mon code provient d'un autre code que j'ai réussi à faire marcher en assemblant des morceaux trouvés sur le net! du coup c'est peut être inutile. Je voulais être sûr qu'il cherche dans chacune des colonnes et sélectionne la bonne.

Tu parcours les colonnes pour récupérer celles qui contiennent Table1 en ligne 1 : également à confirmer ! Récupérer chaque nom de donnée de la ligne 1 de mon fichier principal pour chercher dans les deux bases de données est en effet mon but. J'utiliserai une boucle pour cela. Pour l'instant je veux juste le faire directement depuis le code comme tu peux le voir à cette ligne "If Range("a" & i) Like "*Table1*" Then Columns(i).Select"

Tu les affectes sur ta feuille cible, la 1re en col. G, la 2e en col. I, la 3e en col. K, etc. : encore à confirmer ! En effet pour les données issues de la 1ere database. Les colonnes H, J et L acceuilleront les colonnes issues de la seconde database. Je n'implémente pas cette partie là car pour moi, si j'arrive à faire venir les données de la première, j'y arriverai également pour la seconde!

Pour le second classeur, la même affectation se fera alors en H, J, L, etc. : toujours à confirmer ! Oui, répondu au dessus

Là il nous faut des variables supplémentaires... i représente la colonne source, il n'est pas dit que toutes les colonnes contiennent Table1 (sinon pourquoi tester !), il faut donc gérer l'affectation avec d'autres variables... Il n'y a pas deux données d'une même database avec un même nom. Cependant mes deux databases possèdent exactement les mêmes données (à priori dans le même ordre) mais avec des valeurs différentes évidemment.

En attendant, ces confirmations (ou non) autres remarques sur le code :

  • les déclarations de variables se placent toutes et toujours en tête de procédure, avant la 1re ligne de code exécutable Je devrais donc déclarer "i" au même moment que "principal" et "repertoire"?
  • ThisWorkbook est une propriété que VBA met à ta disposition et qui à tout moment ne peut désigner qu'un objet et un seul ! Vouloir le reprendre dans une autre variable n'est pas très cohérent, et du temps perdu, tant qu'à affecter un objet, autant le faire pour la feuille cible. Si je comprends bien, le "principal" déclaré en tant que destination lors du paste ne correspond pas à mon fichier cible?
  • Toutes les expressions méritent d'être qualifiées par les objets auxquels elle réfèrent (Classeur, Feuille, etc.) et non seulement un échantillon, on y gagne en fiabilité et rapidité Donc je devrais définir la feuille ou le classeur par son nom directement?
  • Dans la boucle i il ne doit évidemment pas y avoir d'instruction concernant le classeur, telle que Close (là ta boucle serait courte, on ne transfère qu'une colonne et on ferme !)
A moins que ce ne soit le but et que Table1 ne peut figurer que dans une colonne... ! Mais dans ce cas tu n'aurais que 2 colonnes au total, donc cela semble incohérent... Mais tu vaas préciser tout ça. Je cherche en effet à rappatrier une quinzaine de colonnes de données de chaque database.

Merci encore pour ton aide! Je suis néophyte en VBA et le code m'a toujours donné des boutons! j'essaie de m'y mettre et de nombreux points restent très sombres

C'est pas gagné ! Tu lances une boucle destiné à tout faire et tu ne mets en route la programmation que d'une petite partie.

Donc première révision qui s'impose c'est : on va tout faire d'un seul coup !

Ok pour 2 bases, ça simplifie.

Au niveau de l'initialisation de la boucle, ta syntaxe était totalement incorrecte, Range définie avec 2 réf. de colonnes et pas de lignes et utilisation de xlUp qui ne peut concerner que recherche de ligne au lieu de xlToLeft... (entre autres) mais chaque chose en son temps, les pbs de syntaxe se règlent vite lorsque ce que l'on veut faire est bien défini.

La question de fond à cet égard est : entends-tu récupérer les colonnes de la base dans l'ordre, au quel cas c'est simple, on les prend dans l'ordre et on les espace d'une colonne sur la cible. Ou bien dans un ordre différent, auquel cas il faut identifier chaque colonne et savoir à l'avance dans quel ordre on va la mettre sur la cible.

(Ne cherche pas ce qui est plus simple... Il faut penser au résultat qu'on veut, rien n'est vraiment simple mais on trouve toujours une méthode pour le faire !)

Ok pour les affectations alternées...

Si tu mets le nez dans VBA, en général ce n'est pas pour l'abandonner le lendemain, tu y seras toujours 20 ans après... (sous réserve d'évolutions... ). Il faut donc distinguer dès maintenant deux aspects importants en matière de code, ce qui intéresse celui qui le fait ou le modifie (la présentation, les façons de raccourcir le code nécessaire, ce qui permet de le lire plus vite en interprétant à mesure), ça VBA s'en fout s'il peut exécuter, il exécute, c'est celui qui écrit ensachant autant que possible ce qu'il écrit ou qui doit chercher pourquoi VBA n'exécute plus que cela intéresse d'abord. Et il y a ce qui va permettre une exécution plus rapide et sans risque d'erreurs, ce qu'on désigne souvent par optimiser. Les deux aspects sont liés par le fait que celui qui optimise doit pouvoir lire rapidement... et aussi que certaines facilités d'écriture concourent également à une meilleure exécution. Mais ils sont distincts en ce sens qu'un code mal écrit (que je refuserais même de regarder ) pourra cependant s'avérer optimal alors qu'un code bien présenté, selon les règles pourra cumuler des commandes aboutissant à ralentir l'exécution.

Mes remarques mélangent les deux aspects mais tu apprendra à faire le tri pour bien distinguer ce qui est impacté.

Le cas de ThisWorkbook : c'est une propriété de l'objet Application qui désigne toujours le classeur contenant la macro qui l'invoque.

Tu affectes des variables pour deux raisons principales : pour faciliter l'écriture et parce que l'accès aux variables est plus rapide lors de l'exécution. Dans ce cas, une variable ne présente aucun avantage supplémentaire à l'utilisation directe de ThisWorkbook, tout au plus raccourcir (mais avec principal tu ne raccourcis pas beaucoup !) et tu n'as que peu à l'invoquer s'agissant du classeur à partir duquel tu manipules les autres. Par contre, une variable Worksheet pour y affecter la feuille cible, te raccourcit nettement l'expression à écrire pour la pointer et t'ouvre un accès direct plus rapide à ladite feuille...

La déclaration des variables en tête de procédure, là c'est une convention d'écriture en premier lieu : on gagne du temps en n'allant chercher ailleurs la façon dont elles ont été déclarées. En même temps, on garantit qu'une variable a été déclarée avant d'être utilisée (c'est rare mais ça a pu arriver ! et ça peut poser quelques problèmes...). Mais on est surtout ici dans des conventions d'écriture.

Après, un problème récurrent que j'ai évoqué, les qualificateurs d'objets : ça vaut pour tous les objets mais on le voit surtout pour les objets Range (Range, Cells, Rows, Columns, Areas, etc. (Pour d'autres, on est obligé le plus souvent de qualifier pour que cela fonctionne...) Ce qu'il faut comprendre, c'est que quand tu utilises Range (ou autre expression destinée à renvoyer un objet Range) ce n'est un appel d'objet directement que tu fais (tu n'en fais d'ailleurs jamais dans le code...) Tu utilises la propriété Range d'un objet Worksheet qui va renvoyer un objet. La nuance est sensible, on ne touche pas aux objets, si l'on peut dire, dans le code on les renvoie à partir de l'objet parent de niveau supérieur dans le modèle d'objets Excel. On part donc de l'Application, qui est une et qui est le souvent invoquée implicitement (mais quand tu dois l'invoquer explictement, tu écris Application, qui est une propriété de l'objet Application et qui renvoie l'Application Excel en cours d'exécution), le classeur (Workbook) : on travaille souvent avec un seul classeur et on peut alors faire l'impasse, mais on ne travaille quasiment jamais ou jamais durablement avec une seule feuille. Donc l'utilisation renvoyant un objet Range, sans référence explicite à l'objet parent conduit VBA à le rattacher à la feuille active du classeur actif et à rechercher cette dernière. Si tu le lui dis, il gagne du temps. Si tu dois t'y référer plusieurs fois, tu as toujours intérêt à le faire dans une instruction With car VBA la met alors en mémoire et y rattachera automatiquement toutes les expressions précédées d'un point. Gain en écriture, mais surtout gain de rapidité.

On reviendra aussi sur le copier-coller, si c'est la seule méthode de transfert de données dont tu disposes dans Excel manuellement. Ce n'est pas le cas avec VBA. Copier, c'est transiter par le presse-papier de Windows, VBA peut s'en passer s'il s'agit d'affecter des valeurs...

Apèrs cette digression, je résume : la seule question restant à examiner est l'ordre des colonnes, ou bien leur identification, à l'instar de la première dans ton code initial.

Cordialemnt.

Bonjour,

J'ai suivi tes instructions et ai déclaré toutes mes variables au début de mon code. J'ai également modifié le xlup en xltoleft! Par contre, je n'ai pas tout compris à ce que tu as expliqué concernant ThisWorkbook. Je suis d'accord que dans mon code (qui est un patchwork de lignes de code trouvées sur le net), je ne comprenais pas bien l'intérêt d'affecter ThisWorkbook à la variable principal (surtout le fait qu'il yait à la fois "Dim ThisWorkboos As principal" et "Set ThisWorkbook As principal"). Par contre, je ne comprends pas bien comment affecter la feuille cible à Worksheet. De plus, mes fichiers de bases de données ne comportent qu'une seule feuille, ils sont enregistrés au format .aif qui correspond à un .csv.

Concernant les colonnes, je suppose qu'il s'agit d'un ordre différent. Le problème c'est qu'à parler de données, je ne sais plus quand on parle des valeurs prise par la voie Table 1 où de toute la colonne Table1 en même temps...

Pour être sûr, mon fichier de database comprend dans ses deux premières colonnes le numéro de la donnée et le temps à laquelle la donnée a été acquise. elles sont donc triées par ordre d'acquisition et donc par ordre temporel croissant également. Pour ce qui est de la colonne Table1, elle peut se retrouver dans mon fichier de database 1 en colonne VXA et dans mon fichier de database 2 en colonne VXE par exemple. D'où le fait que je souhaitais les trouver par nom et nom par numéro de colonne! Je me rends compte que je disais le contraire dans mon premier message et il s'agissait d'une erreur, désolé!

Bonjour,

J'ai un peu de mal à te suivre...

Ceci :

    Dim principal As ThisWorkbook
    Set principal = ThisWorkbook

ne t'avance strictement à rien !

Par contre :

    Dim wsC As Worksheet, repertoire$, fichier$, i&
    Set wsC = ThisWorkbook.Worksheets("Données")

cela oui ! tu réfèreras directement à ta feuille cible avec la variable lors du recueil de données...

Et d'autre part :

        Workbooks.Open (repertoire & fichier)

Là les parenthèses sont de trop (ça marche parce qu'elles ont une signification autre qui n'a pas d'incidence ici, elles doivent par contre être mises lorsque l'expression est à droite d'un signe = ou que l'expression se poursuit pour faire appel à une autre propriété ou méthode, comme ci-dessous).

        With Workbooks.Open(repertoire & fichier).Worksheets(1)

Là, tu ouvres le classeur en insérant simultanément sa première feuille (le fait qu'il n'en possède qu'une ne dispense pas d'y faire référence pour accéder à son contenu !) dans un bloc With... End With (à l'intérieur duquel, les expressions référant à la feuille seront simplement précédées d'un point, d'où gain en écriture et clarté du code...)

Ensuite, la question était de savoir si on prélevait une, plusieurs ou toutes les colonnes, et comment les disposer sur la cible selon les cas. Puis si prélèvement dans l'ordre ou selon autre critère : ta mention Table va dans le sens autre critère, mais dans ce cas il faut être complet : quels sont les critères pour prélever chaque colonne dans l'ordre voulu, tant qu'on n'en a qu'un on ne peut en prélever qu'une...

La mise au point de ton code exige : une boucle pour ouvrir et fermer tour à tour chaque classeur (manquante dans code initial), dans cette boucle, un critère de ciblage (décalage ?) permettant de définir les colonnes cibles selon le classeur source est à établir, une boucle incorporée devra permettre de parcourir les colonnes source dans l'ordre de prélèvement (donc, parcours en désordre !), à ce stade, prélèvement et affectation à la cible ne sont pas un problème... Les colonnes cibles vont alterner pour chaque source (décalage de 1 des cibles de la seconde par rapport aux cibles de la première), cela peut se définir, mais ce qui manque toujours, ce sont les colonnes à prélever (critères successifs) dans l'ordre d'affectation à la cible...

Cordialement.

Merci pour tes précisions!

Désolé, c'est vrai que ce n'est pas si évident de communiquer clairement mon problème par écrit.

Concernant les données:

Je souhaite extraire certaines colonnes de mes deux databases.

- Pour cibler les colonnes recherchées, comme leur position peut varier d'une database à l'autre, je souhaite les rechercher via leur nom d'entête (TABLE1, TABLE2, CHAISE, etc...). Je souhaite renseigner les noms d'entête directement dans mon fichier principal en ligne 1. Je souhaitais que la macro lise ces noms d'entête pour les chercher dans la database, sélectionner la colonne entière et la copier dans mon fichier principal.

  • Je n'ai pas affiché beaucoup de noms d'entête différents dans mon fichier mais mes databases contiendront plusieurs centaines de colonnes et je souhaiterai en extraire vers mon classeur principal seulement une quinzaine
  • Comme tu l'as bien compris, je souhaite mettre les données de TABLE1 de la database1 en G, les données TABLE1 de la database2 en H, les données de TABLE2 de database1 en I etc...
  • Dans l'absolu, plutôt que de copier la colonne entière TABLE1 en G dans mon fichier principal, je préférerais transférer (copier/coller ou tout autre moyen est bon à prendre ) juste les unités et valeurs numériques se trouvant à partir de la ligne 2 dans mes databases. J'étais parti sur la copie de la colonne entière car cela me paraissait plus simple dans un premier temps.

Je t'ai joint un exemple de database, le fichier est au format .csv car impossible d'uploader un fichier en .aif. Je ne peux pas uploader les vraies databases pour des raisons de confidentialité mais J'espère que cet exemple t'aidera à y voir plus clair dans mon charabia!

Merci d'avance.

21database1.csv (7.98 Ko)
Rechercher des sujets similaires à "extraire donnees deux databases comparer"