Macro fusion de plusieurs colonnes sans doublon avec filtre
Bonjour le forum,
Je viens vers vous aujourd'hui étant mon problème que je n'arrive pas à résoudre seul avec mes compétences actuelles en VBA :
- J'aimerais pouvoir fusionner 3 colonnes se trouvant sur 3 feuilles différentes, avec comme lieu d'arrivée une quatrième feuille ou la macro copierait la totalité de la liste triée sans doublon.
- A savoir qu'elles n'ont pas le même format, c'est à dire, pas les mêmes noms de colonne, ni le même emplacement ( colonne E pour l'une, G pour l'autre, etc..), de plus j'aimerais pouvoir appliquer des filtres personnalisés sur chaque BDD avant leur fusion, filtres ici encore une fois différents pour chaque BDD étant donné que ce sont 3 systèmes d'information n'étant pas censé communiquer entre eux.
Si vous avez peut-être des suggestions, programmes existants je suis preneur, le graal serait de pouvoir avoir un programme qui puisse être assez facilement modifiable si je dois décaler une colonne etc.. , je vous transmets ci-joint un fichier exemple, avec 3 BDD et une feuille "d'arrivée"
merci d'avance pour votre aide :)
cordialement,
3 manières de copier et coller, puis sorter et effacer les doublons
Sub test()
With Sheets("fusion_3_BDD")
Sheets("BDD1").ListObjects(1).ListColumns(2).DataBodyRange.Copy '<<< le numéro de la listcolonne
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlValues
Sheets("BDD2").ListObjects(1).ListColumns("Clé_de_correspondance2").DataBodyRange.Copy '<<< le nom de la listcolonne
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlValues
Set c = Sheets("BDD3").ListObjects(1).ListColumns("Clé_de_correspondance3").DataBodyRange
.Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(c.Rows.Count).Value = c.Value 'les valeurs
.Range(.Range("A1"), .Range("A" & Rows.Count).End(xlUp)).Sort .Range("A1"), Header:=xlYes 'sorter toute la colonne
.Range(.Range("A1"), .Range("A" & Rows.Count)).RemoveDuplicates Columns:=1, Header:=xlYes 'no doublons dans cette plage
End With
End Sub@bsAlv, merci ! étant donné que j'aurais des BDD conséquentes, centaines voire milliers de ligne, y'en a t'il une plus rapide ? et pour ce qui est des filtres à appliquer dans les tableaux des 3 BDD, cela fonctionnera t'il avec les 3 méthodes ?
cordialement,
si vous avez des tableaux filtrés a ce moment, la méthode 3 ne fonctionnera pas, parce qu'elle copie et colle tout, aussi les lignes cachées.
Concernant la vitesse et des milliers de lignes, il n'y a pas de problèmes tant que vous ne dépassez pas les limites de la feuille (nombre de lignes >1.048.000), vitesse = quasi instantément
Ok, merci, je vais regarder tout ça :)
concernant le nom de la colonne, y-a-t-il quelque chose unique en commun, par exemple "Clé_de_correspondance" ou "correspondance" ?
Actuellement non. Mais je pourrais modifier à l'avenir tout cela si j'en ai besoin. 2 des 3 colonnes sont des colonnes calculées et rajoutées par moi-même ( la 3 ème est déjà "pré-crée par le système d'information qui nous la fournie lors de l'extraction). Je pourrais donc modifier les 2 colonnes pour les faire correspondre à la 3ème sans soucis.
Pourquoi cette question ?
Pour ce qui est du code, lorsque je le lance, la liste semble correcte, parfait, mais je suis téléporté dans le bas de la feuille ligne 4619 avec en sélection plus de 900 lignes, bizarre d'autant plus que ma liste finale se termine à la ligne 2493. Auriez-vous une piste ? ( cela ne me le faisait pas dans le fichier originel)
--> en mode pas à pas, cela semble être où la dernière BDD est copiée avant suppression des doublons --> copie en ligne 4619 de la 3ème BDD, y remédier en faisant une sélection sur la case A1 peut-être ?
PS : je n'utilise que les deux premières méthodes
merci d'avance :)
no, je n'ai pas de piste, sauf cela a quelque chose à faire avec ce "end(xlup)", mais c'est à résoudre avec "Application.goto"
Dans cet exemple, j'ai ajouté un tableau qui guide la macro avec nom de tableaux et colonnes.Donc, on ne doit plus changer la macro quand quelque chose autre change.
Et un exemple de chercher la colonne avec le mot "clé" dedans
Sub test()
t = Timer
With Sheets("fusion_3_BDD")
a = .ListObjects("TBL_Macro").DataBodyRange.Value
'EXEMPLE POUR CHERCHER LA LISTCOLUMN QUI CONTIENT LE MOT "CLE"
entetes = Application.Transpose(Application.Transpose(Range(a(1, 1)).ListObject.HeaderRowRange.Value)) 'les entetes du listobject qui correspond avec la premiere ligne du tableau TBL_Macro
fl = Filter(entetes, "clé", 1, 1) 'filtrer ces entetes avec "cle" dedans
colonne = Application.Match(fl(0), entetes, 0) 'la premiere colonne qui contient "clé"
MsgBox "c'est colonne " & colonne
For i = 1 To UBound(a)
Range(a(i, 1)).ListObject.ListColumns(a(i, 2)).DataBodyRange.Copy '<<< le nom du tableau et ou le nom de la colonne ou le numéro de la colonne
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlValues
Next
Application.Goto .Range("A1") 'positionner sur cette cellule
.Range(.Range("A1"), .Range("A" & Rows.Count).End(xlUp)).Sort .Range("A1"), Header:=xlYes 'sorter toute la colonne
.Range(.Range("A1"), .Range("A" & Rows.Count)).RemoveDuplicates Columns:=1, Header:=xlYes 'no doublons dans cette plage
End With
MsgBox "prêt en " & Format(Timer - t, "0.0\s") 'temps si l'autre msgbox n'etait pas là
End Sub
Bonjour,
merci pour cette nouvelle idée ! cela permettrait que d'autres utilisateurs puissent le modifier facilement sans devoir modifier le code en dur, mais le problème est que j'ai des filtres sur des colonnes que j'aimerais appliquer dans chacun des tableaux, ces filtres seraient différents d'une feuille à une autre étant donné que les BDD ne se ressemblent pas, et de ce que j'ai compris de ce code est qu'il Copie + colle à l'aide d'une boucle..
For i = 1 To UBound(a) --> c'est cette variable i qui m'indique le numéro de la feuille et donc sur laquelle je dois effectuer ma boucle conditionnelle pour appliquer un filtre uniquement dans ce tableau avant de copier ?
merci par avance :)
bonjour,
non, il faut regarder au tableau "TBL_Macro" (commence à E1 de la feuille fusion_3_BDD) , la macro lit son contenu dans la matrice a.
Le nombre de lignes de ce tableau est ubound(a) et le "for ... next" fait donc ubound(a) boucles.
la première colonne de TBL_Macro contient tous les noms des tableaux que vous voulez utiliser et la 2ième colonne contient le nom de la colonne de ce tableau ou le numéro de la colonne de ce tableau.
exemple 1 : première ligne du TBL_Macro : i = 1 >>> a(1,1) = Tableau 1 et a(1,2) = Clé_de_correspondance1, donc ...
Range(a(i, 1)).ListObject.ListColumns(a(i, 2)).DataBodyRange.Copy >>>>
Range(a(i,1)) = la plage des données de ce tableau sans les entêtes, donc Tableau1
Le ".listobject" fait de cette plage un tableau
Le ".listcolumns(....)" prend de ce tableau la colonne définit entre les parathèses (numérique ou texte, ici texte), dans ce cas "Clé_de_correspondance1"
Le .databodyrange prend la plage des données de cette listcolumn
et ... Copy tout cela en dessous la colonne A de Fusion_3_BDD.
exemple 2 = 2ième ligne de TBL_Macro : i = 2 >>> a(2,1) = Tableau 13 et a(2,2) = 3, donc ...
la plage a copier vient du tableau "Tableau 13" et comme a(2,2)=3 est numérique, donc la 3ième colonne.
etc
Donc le nombre de lignes dans tableau "TBL_Macro" est le nombre de tableaux que vous voulez fusionner.
Bien remarqué : Le filtrage de ces 3 tableaux (manuellement ou VBA) doit se faire avant le lancement de cette macro.
Ok.. je vois mieux, merci beaucoup, si je veux placer ce TBL_Macro sur une feuille à l'écart, c'est possible sans trop de modification ? j'ai peur de faire des bêtises :)
si ce tableau reste dans le même fichier.
(Pour le moment, je n'utilise pas la construction "With ... End With")
2 possibilités,
a = Sheets("Autre Feuille").ListObjects("TBL_Macro").DataBodyRange.Value
a = Range("TBL_Macro").ListObject.DataBodyRange.Valueremarque : 2ième ligne, c'est Listobject (sans dernier "s") et on ne doit pas préciser la feuille
Bonjour !
Merci pour cette information ! (je n'avais pas reçu de notification).
Je viens de me rendre compte qu'il existe des cas particuliers. Mes "clés" me permettant de faire la correspondance entre les 3 BDD sont simplement la concaténation d'un nom de matériel ainsi que d'un numéro de série, exemple : matériel1_0100, par la suite lorsque les doublons ont été triés, à l'aide de formule je vérifie si la clé est présente dans les BDD, et j'affiche un récap de tout ça... or comme je l'avais dit précédemment, les BDD ne sont pas standardisées et n'ont pas été conçues pour communiquer entre-elles, c'est pour cela que je peux avoir un cas particulier... : matériel1_0100 / maériel1_100 --> même matériel avec le même numéro de série mais ils sont considérés comme différents lorsque je trie les doublons. Ma question est la suivante, existe t'il un code assez simple pour pouvoir supprimer matériel_0100 si matériel_100est présent (je saurais le faire via des formules excels mais ici impossible) ?
j'imagine qu'il faudrait l'implanter juste après avoir copié l'ensemble des 3 BDD mais juste avant avoir supprimer les doublons.
Merci d'avance, pour votre aide :)
bonjour,
la partie après "Application.goto ... " jusqu'à "End with" est modifié un petit peu. La macro contrôle pour chaque cellule la partie après le dernier "_", si cela est numerique, elle le remplace par son valeur.
Sub test()
t = Timer
With Sheets("fusion_3_BDD")
a = .ListObjects("TBL_Macro").DataBodyRange.Value
'EXEMPLE POUR CHERCHER LA LISTCOLUMN QUI CONTIENT LE MOT "CLE"
entetes = Application.Transpose(Application.Transpose(Range(a(1, 1)).ListObject.HeaderRowRange.Value)) 'les entetes du listobject qui correspond avec la premiere ligne du tableau TBL_Macro
fl = Filter(entetes, "clé", 1, 1) 'filtrer ces entetes avec "cle" dedans
colonne = Application.Match(fl(0), entetes, 0) 'la premiere colonne qui contient "clé"
MsgBox "c'est colonne " & colonne
For i = 1 To UBound(a)
Range(a(i, 1)).ListObject.ListColumns(a(i, 2)).DataBodyRange.Copy '<<< le nom du tableau et ou le nom de la colonne ou le numéro de la colonne
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlValues
Next
Application.Goto .Range("A1") 'positionner sur cette cellule
With .Range(.Range("A1"), .Range("A" & Rows.Count).End(xlUp)) 'les données
a = .Value 'lire plage >>> matrice
For i = 2 To UBound(a) 'boucle mais ne pas l'entête
sp = Split(a(i, 1), "_") 'séparer sur le "_"
If IsNumeric(sp(UBound(sp))) Then 'la dernière partie est numerique
sp(UBound(sp)) = --sp(UBound(sp)) 'remplacer ce string par son valeur (=eliminer les "leading" zéros)
a(i, 1) = Join(sp, "_") 'adapter la matrice
End If
Next
.Value = a 'écrire matrice >>> plage
.Sort .Range("A1"), Header:=xlYes 'sorter toute la colonne
.RemoveDuplicates Columns:=1, Header:=xlYes 'no doublons dans cette plage
End With
End With
MsgBox "prêt en " & Format(Timer - t, "0.0\s") 'temps si l'autre msgbox n'etait pas là
End Sub
Re,
Merci beaucoup, je vais essayer tout ça ! :)