Formules en VBA pour tableau structuré
bonjour;
dans les trois premières colonnes de la feuille 'dexp' j'ai decortiqué à la lumière des définition des codes en feuille 'param' le code qui est en colonne Tag de la feuille data,
comme mon vrai fichier comporte des milliers de lignes je galère pour copier en glissant les formules; je cherche alors à faire ces formules en vba
exemple pour le site: si le code est en 14 caractère alors soustraire le nom du site comme ceci (parfois le code est 15 caractère comme c le cas des dernières lignes)
=SIERREUR(SI(NBCAR(TAB_DATAfx[@Tag])=14;INDEX(TAB_ville_site;EQUIV(STXT(TAB_DATAfx[Tag];1;9);TAB_ville_site[VILLE.SIT_C];0);3);INDEX(TAB_ville_site;EQUIV(STXT(TAB_DATAfx[Tag];1;10);TAB_ville_site[VILLE.SIT_C];0);3));"")comment faire ça en vba??
merci d'avance
Bonjour,
Vous positionner sur la cellule contenant la formule.
Basculer dans l'éditeur VBA, faire apparaitre la fenêtre exécution avec Ctrl-G
Dans la fenêtre exécution, taper la formule ?ActiveCell.Formula
La formule va être traduite en VBA. Il restera à doubler les "", là où ils apparaissent.
Bonjour Eric, Kamel,
je propose ceci, cette macro met la ville, le site et la mesure dans une plage à côté de votre tableau (ou on pouvait aussi l'ajouter au tableau).
Sub Kamel()
Dim LO, cVille, cMes, cSite, aA, aOut, i, sp, x, s
Set LO = Sheets("data").Range("A1").ListObject 'tableau de vos données
Set cVille = Sheets("param").ListObjects("TAB_Ville").DataBodyRange 'plage du tableau de vos villes
Set cMes = Sheets("param").ListObjects("TAB_Mes").DataBodyRange 'plage du tableau de vos mesures
Set cSite = Sheets("param").ListObjects("TAB_ville_site").DataBodyRange 'plage du tableau de vos sites
aA = LO.DataBodyRange.Columns(1).Value2 'lire 1ière colonne de vos données
ReDim aOut(1 To UBound(aA), 1 To 3) 'preparer un tableau avec le même nombre de lignes et 3 colonnes
On Error Resume Next
For i = 1 To UBound(aA) 'boucler vos données
sp = Split(aA(i, 1), ".") 'diviser sur le "."
aOut(i, 1) = WorksheetFunction.VLookup(sp(0), cVille, 2, 0) 'rechercher la ville
aOut(i, 2) = WorksheetFunction.VLookup(sp(0) & "." & sp(1), cSite, 3, 0) 'rechercher le site
aOut(i, 3) = Application.WorksheetFunction.VLookup(sp(2), cMes, 2, 0) 'rechercher la mesure
If Err.Number <> 0 Then s = s & ", " & i: Err.Clear
Next
On Error GoTo 0
LO.DataBodyRange.Offset(, 10).Resize(, 3).Value = aOut 'coller les résultats à côté du tableau initial
If Len(s) Then MsgBox Mid(s, 3), vbInformation, "lignes avec des erreurs"
End SubBonjour,
Une approche Power Query.
Cdlt.
Bonjour Eric Kergresse, Bart et Jean-Eric
Ce matin j'ai eu juste le temps de tester la petite astuce de traduction de Eric Kergrese, et c'est utile !
Bart et Jean Eric je vais examiner vos propositions dès que j'aurais un peu de temps libre merci à tous pour l’intérêt accordé.
Je vous tiens au courant.
@tt
Bonjour à tous
comme mon vrai fichier comporte des milliers de lignes je galère pour copier en glissant les formules; je cherche alors à faire ces formules en vba
Un double clic sur la poignée de recopie de la cellule suffit à recopier jusqu'en bas
Inutile de coder pour cela !
Re bonsoir ;
@ Jean-Eric ta méthode fonctionne, j jeté un coup d’œil sur les étapes , je suppose qu’elle utilise la même approche que la macro de Bart sauf qu’en power query, mais pour moi qui a le défaut de ne pas avoir un « bon appétit » pour les méthodes power query, pourtant puissantes, je la garde pour y revenir au besoin. Merci.
@ Bart est -il possible de me donner quelques éclaircissements :
1 / pour étendre le tableau et inclure les autres colonnes (day , heure , valeur) si possible tout sur une autre feuille
J essayé aOut(i, 4) = aA(i, 1).Offset(, 1) mais c une grave erreur
Comment écrire aOut(i, 4) en fonction de la colonne N°2 du tableau (l’équivalant de la formule « = TAB_DATAfx[@d] »
2/
Set LO = Sheets("data").Range("A1").ListObject : tu dis que c le tableau de mes données donc c’est ’’TAB_DATAfx’’ ? Je vois que c une curieuse façon de se référer à ce tableau !
3/
aA = LO.DataBodyRange.Columns(1).Value2 : pourquoi Value2 ? 4/
sp = Split(aA(i, 1), "."): pourquoi aA qui est à une dimension devient aA(i, 1) ? Cordialement
Bonsoir 78chris exemple dans ce classeur feuille 'f2' : je double clic sur la croix noir en bas à droite de A2 : rien !
re,
nouvelle version
les dates (et currency/monnaie) se lisent mieux avec Value2. Il faut ajouter des colonnes avec Redim et "preserve". On peut aussi assigner un tableau par une cellule de ce tableau
Sub Kamel()
Dim LO, cVille, cMes, cSite, aA, i, sp, s, sh, MyColumns, iCol, LO2
Set LO = Sheets("data").Range("A1").ListObject 'tableau de vos données = tableau avec cette cellule dans sa plage
Set cVille = Sheets("param").ListObjects("TAB_Ville").DataBodyRange 'plage du tableau de vos villes
Set cMes = Sheets("param").ListObjects("TAB_Mes").DataBodyRange 'plage du tableau de vos mesures
Set cSite = Sheets("param").ListObjects("TAB_ville_site").DataBodyRange 'plage du tableau de vos sites
aA = LO.Range.Value2 'lire vos données & entêtes complètement (avec dates ou currency toujours Value2 (!))
ReDim Preserve aA(1 To UBound(aA), 1 To UBound(aA, 2) + 3) 'ajouter 3 nouvelles colonnes vides, mais conserver le reste
aA(1, UBound(aA, 2) - 2) = "Ville" 'première nouvelle colonne sera "ville" (entête)
aA(1, UBound(aA, 2) - 1) = "Site" '2ième nouvelle colonne sera "Site" (entête)
aA(1, UBound(aA, 2)) = "Mesure" 'dernière nouvelle colonne ser "Mesure" (entête)
On Error Resume Next 'continuer en cas d'erreur, si par exemple, on ne trouve pas la ville, le site ou la mesure
For i = 2 To UBound(aA) 'boucler vos données sans les entêtes
sp = Split(aA(i, 1), ".") 'diviser sur le "."
aA(i, UBound(aA, 2) - 2) = WorksheetFunction.VLookup(sp(0), cVille, 2, 0) 'rechercher la ville
aA(i, UBound(aA, 2) - 1) = WorksheetFunction.VLookup(sp(0) & "." & sp(1), cSite, 3, 0) 'rechercher le site
aA(i, UBound(aA, 2)) = Application.WorksheetFunction.VLookup(sp(2), cMes, 2, 0) 'rechercher la mesure
If Err.Number <> 0 Then s = s & ", " & i: Err.Clear 'on sauvegarde toutes les lignes avec des erreurs
Next
On Error GoTo 0
Set sh = Sheets.Add(after:=Sheets(Sheets.Count)) 'ajouter une nouvelle feuille
MyColumns = Array(2, 3, 5, 6, 7, 4) 'supposons(!) qu'on veut cette séquence de colonnes, pas la séquence originale
With sh.Range("A1").Resize(UBound(aA), UBound(MyColumns) + 1) 'plage pour nos données avec autant de colonnes
For iCol = 0 To UBound(MyColumns)
.Offset(, iCol).Resize(, 1).Value = Application.Index(aA, 0, MyColumns(iCol))
Next
.Columns(1).NumberFormat = "dd/mmm/yy" 'date
.Columns(2).NumberFormat = "hh:mm:ss" 'heure
.EntireColumn.AutoFit
Set LO2 = .Parent.ListObjects.Add(Source:=.Offset(0)) 'c'est un tableau maintenant
End With
If Len(s) Then MsgBox Mid(s, 3), vbInformation, "lignes avec des erreurs"
End SubBonjour
Bonsoir 78chris exemple dans ce classeur feuille 'f2' : je double clic sur la croix noir en bas à droite de A2 : rien !
Pour que la poignée de recopie fonctionne il faut avoir une colonne déjà remplie à gauche ou à droite
Dans ton cas :
- sélectionner la valeur ou la formule et la copier
- taper dans la zone de nom l'adresse de dernière cellule: A5000 par exemple
- utiliser CTRL flèche haut puis coller
Pour 4 colonnes, on copie les 4 cellules et, entre l'étape 2 et 3, on sélectionne les 4 cellules de la ligne 5000
Bonjour; c résolu
@Bart ça marche
je reviens si je ne comprend pas quelque chose car mon but n'est pas seulement de résoudre mais de mieux comprendre.
@78chris ça marche aussi (théoriquement, tel que mon problème est posé, ta façon suffit, mais j'imagine qu'il y a des cas où il est mieux avec macro (Bart peut-être peut dire quelque chose?) )
Merci à tous
@tt
re,
@Bart : juste quelques explications : franchement j'ai du mal à comprendre le aA et sa manipulation:
UBound(aA, 2) = nb de colonnes ! existe-t-il UBound(aA, 3) ? par exemple?
aussi:
sh.Range("A1").Resize(UBound(aA), UBound(MyColumns) + 1).Offset(, iCol).Resize(, 1).Value = Application.Index(aA, 0, MyColumns(iCol))
dans index pourquoi le 0 (Row_num =0 ?)
et index ici s'applique d'un seul coup à toutes les lignes ?
@tt
re,
si aA a 3 dimensions, oui
Sub test()
Dim aA(1 To 4, 2 To 5, 3 To 6)
For i = 1 To 3
MsgBox LBound(aA, i) & " " & UBound(aA, i) 'lowerbound and upperbound
Next
End Subce 0 veut dire toutes les lignes (on peut aussi utiliser une sélection de lignes).