J'ai 2 tableaux sur 2 feuilles séparées d'un classeur MS Excel 2007, comme ci-dessous:
===========================
no. f_name l_name
===========================
13 Little Timmy
1 John Doe
17 Baby Jessica
---------------------------
===========================
no. f_name l_name
===========================
1 john Tim
16 kyle joe
14 Baby katy
22 qbcd wsde
---------------------------
Les deux ont les mêmes colonnes, mais ils peuvent avoir des données différentes.
Je souhaite combiner les données des deux tables verticalement, c’est-à-dire un tableau unique contenant toutes les données d’une troisième feuille séparée. Si possible, je souhaite ajouter une autre colonne avec le nom de la feuille d'où provient la ligne.
===================================
SheetName no. f_name l_name
===================================
Sheet1 13 Little Timmy
Sheet1 1 John Doe
Sheet1 17 Baby Jessica
Sheet2 1 john Tim
Sheet2 16 kyle joe
Sheet2 14 Baby katy
Sheet2 22 qbcd wsde
-----------------------------------
Peut-on le faire sans utiliser de macros?
Cette réponse traite de Structured Tables tel qu'interprété par Excel. Bien que les méthodes puissent facilement être transcrites en matrices de données brutes sans structure de tableau attribuée, les formules et le codage VBA pour cette solution seront ciblés sur de véritables tableaux structurés.
Une troisième table peut conserver les données combinées de deux tables avec certaines formules de feuille de calcul natives, mais le maintien de la taille correcte de la troisième table au fur et à mesure de l'ajout ou de la suppression de lignes dans les tables dépendantes nécessitera soit des opérations de redimensionnement manuel, soit du VBA permettant de suivre ces modifications et de s'y conformer la troisième table pour convenir. J'ai inclus des options pour ajouter le nom de la feuille de calcul de la table source ainsi que du code VBA de maintenance de table à la fin de cette réponse.
Si tout ce que vous voulez, c'est un classeur d'exemple opérationnel sans toutes les explications, passez à la fin de cette réponse pour rechercher un lien vers le classeur utilisé pour créer cette procédure.
J'ai utilisé les exemples de données du PO pour construire deux tables nommées (par défaut) Table1 et Table2 sur les feuilles de calcul Sheet1 et Sheet2 respectivement. Je les ai volontairement décalés à différents degrés depuis la cellule A1 de chaque feuille de calcul afin de démontrer la capacité d'un tableau structuré à s'adresser lui-même ou à un autre tableau structuré d'une formule en tant qu'entité distincte, quelle que soit sa position dans la feuille de calcul parent. La troisième table sera construite de la même manière. Ces compensations sont à des fins de démonstration uniquement; ils ne sont pas nécessaires.
Construisez les en-têtes de la troisième table et sélectionnez cette ligne d'en-tête future et au moins une ligne en dessous de celle-ci pour baser la commande Insérer ► Tables ► Table.
Votre nouveau troisième tableau vide sur la feuille de calcul Sheet3 devrait ressembler à ce qui suit.
Commencez par renseigner la première cellule de la DataBodyRange de la troisième table. Dans cet exemple, il s'agirait de Sheet3! C6. Tapez ou collez la formule suivante dans C6 en gardant à l'esprit qu'elle est basée sur les noms de table par défaut. Si vous avez modifié les noms de vos tables, ajustez-les en conséquence.
=IFERROR(INDEX(Table1, ROW([@[no.]])-ROW(Table3[#Headers]),COLUMN(A:A)), INDEX(Table2, ROW([@[no.]])-ROW(Table3[#Headers])-ROWS(Table1),COLUMN(A:A)))
Le fonction INDEX récupère d’abord chaque ligne disponible dans Table1 . Les numéros de ligne réels sont dérivés avec le fonction ROW en référençant des parties définies du tableau structuré avec un peu de maths. Lorsque Table1 est à court de lignes, la récupération est transmise à une seconde fonction INDEX faisant référence à Table2 par fonction IFERROR et ses lignes séquentielles. sont récupérés avec le ROW et fonctions ROWS en utilisant un peu plus de maths. La fonction COLUMN est utilisée en tant que COLUMN(A:A)
qui va extraire la première colonne de la table référencée, où qu'elle se trouve dans la feuille de calcul. Cela passera à la deuxième, troisième, etc. colonne lorsque la formule est remplie à droite.
En parlant de remplir à droite, remplissez la formule à droite en E6. Vous devriez avoir quelque chose qui se rapproche de ce qui suit.
Saisissez la poignée de dimensionnement de Table3 (indiquée par la flèche orange dans l'exemple d'image ci-dessous) dans le coin inférieur droit et faites-la glisser d'une colonne à droite pour ajouter une nouvelle colonne au tableau. Renommez le libellé d'en-tête en un nom plus approprié que celui par défaut. J'ai utilisé Sheet comme libellé de colonne.
Bien que vous ne puissiez pas extraire directement le nom de la feuille de calcul de la table source, le fonction CELL peut extraire le chemin complet, le nom de fichier et la feuille de calcul de toute cellule d’un classeur enregistré¹, en tant que l’option info_types .
Placez la formule suivante dans la cellule vide de Table3 dans la première ligne de la nouvelle colonne que vous venez de créer.
=TRIM(RIGHT(SUBSTITUTE(CELL("filename", IF((ROW([@[no.]])-ROW(Table3[#Headers]))>ROWS(Table1), Table2, Table1)), CHAR(93), REPT(CHAR(32), 999)), 255))
Compléter le remplissage de la table3
Si vous ne prévoyez pas de terminer ce petit projet avec un VBA pour conserver les dimensions de Table3 lorsque des lignes sont ajoutées ou supprimées de l'une des deux tables source, saisissez simplement la poignée de redimensionnement de Table3 et faites-la glisser jusqu'à ce que vous ayez accumulé toutes les données des deux tables. . Voir le bas de cette réponse pour un exemple d'image des résultats attendus.
Si vous envisagez d’ajouter de la VBA, ignorez toute la population de Table3 et passez à l’étape suivante.
L'automatisation complète d'un processus déclenché par des modifications des données d'une feuille de calcul est mieux gérée par la macro d'événements de la feuille de calcul Worksheet_Change . Etant donné que trois tables sont impliquées, chacune sur leur propre feuille de calcul, la macro Workbook_SheetChange est une meilleure méthode pour gérer les événements de modification de plusieurs feuilles de calcul.
Ouvrez le VBE avec Alt+F11. Une fois que vous l'avez ouvert, recherchez l'explorateur de projet en haut à gauche. S'il n'est pas visible, appuyez sur Ctrl+R pour l'ouvrir. Localisez ThisWorkbook et cliquez avec le bouton droit de la souris, puis choisissez Afficher le code (ou double-cliquez simplement sur ThisWorkbook).
Collez le texte suivant dans le nouveau volet intitulé quelque chose comme Book1 - ThisWorkbook (Code) .
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Select Case Sh.Name
Case Sheet1.Name
If Not Intersect(Target, Sheet1.ListObjects("Table1").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
Case Sheet2.Name
If Not Intersect(Target, Sheet2.ListObjects("Table2").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
End Select
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Private Sub update_Table3()
Dim iTBL3rws As Long, rng As Range, rngOLDBDY As Range
iTBL3rws = Sheet1.ListObjects("Table1").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet2.ListObjects("Table2").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet3.ListObjects("Table3").DataBodyRange.Cells(1, 1).Row - _
Sheet3.ListObjects("Table3").Range.Cells(1, 1).Row
With Sheet3.ListObjects("Table3")
Set rngOLDBDY = .DataBodyRange
.Resize .Range.Cells(1, 1).Resize(iTBL3rws, .DataBodyRange.Columns.Count)
If rngOLDBDY.Rows.Count > .DataBodyRange.Rows.Count Then
For Each rng In rngOLDBDY
If Intersect(rng, .DataBodyRange) Is Nothing Then
rng.Clear
End If
Next rng
End If
End With
End Sub
Ces deux routines utilisent intensivement la feuille de calcul propriété. CodeName . Une Nom CodeName est Sheet1, Sheet2, Sheet3, etc et ne change pas lorsqu'une feuille de calcul est renommée. . En fait, ils sont rarement modifiés, même par les utilisateurs les plus avancés. Ils ont été utilisés pour que vous puissiez renommer vos feuilles de calcul sans avoir à modifier le code. Cependant, ils devraient maintenant pointer vers les feuilles de calcul correctes. Modifiez le code si vos tables et feuilles de calcul ne sont pas identiques à celles données. Vous pouvez voir les noms de code de chaque feuille de calcul entre parenthèses à côté de leur feuille de calcul propriété. Name dans l'image ci-dessus montrant l'explorateur de projet de VBE.
Robinet Alt+Q pour revenir à vos feuilles de calcul. Tout ce qui reste à faire serait de finir de remplir le tableau 3 en sélectionnant une cellule quelconque dans le tableau 1 ou Table2 et feignant de le modifier en tapant F2 puis Enter↵. Vos résultats devraient ressembler à ce qui suit.
Si vous avez suivi jusqu'ici, vous devriez avoir une table de collection assez complète qui combine activement les données de deux tables 'enfants' sources. Si vous ajoutez également VBA, la maintenance de la troisième table de collecte est pratiquement inexistante.
Si vous choisissez de renommer tout ou partie des trois tableaux, les formules de la feuille de calcul refléteront instantanément et automatiquement les modifications. Si vous avez choisi d'inclure la procédure Workbook_SheetChange et l'aide auxiliaire associée, vous devrez revenir à la feuille de code ThisWorkbook et utiliser Rechercher & remplacer pour apporter les modifications appropriées.
Exemple de classeur
J'ai mis à disposition de mon DropBox public un exemple de classeur entièrement opérationnel.
Table_Collection_w_Sheetname.xlsb
¹ Le fonction CELL ne peut extraire que le nom de la feuille de calcul d'un classeur enregistré. Si un classeur n'a pas été enregistré, il ne possède pas de nom de fichier et la fonction CELLU renvoie une chaîne vide lorsque le nom de fichier est demandé.
Vous pouvez activer le Presse-papiers Office (flèche en bas à droite de la section Presse-papiers dans l'onglet Accueil du ruban). Copiez les deux plages, puis utilisez la commande Coller tout comme indiqué ci-dessous.
Vous devez toujours remplir le nom de la feuille dans une colonne supplémentaire en premier lieu, ce qui peut être fait en double-cliquant sur la poignée de recopie.
Mettre à jour
Pour obtenir les mêmes résultats avec les formules, essayez de remplir ceci pour le nom de la feuille:
=IF(ROW()<=COUNTA(Sheet1!A:A),"Sheet1",IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),"Sheet2",""))
puis remplissez cette formule pour les valeurs dans les tableaux:
=IF(ROW()<=COUNTA(Sheet1!A:A),Sheet1!A2,IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),INDEX(Sheet2!A:A,ROW()-COUNTA(Sheet1!A:A)+1),""))
lori_m a fait une très bonne contribution que j'ai construite en utilisant des tableaux Microsoft Excel et des références structurées.
Créez d'abord une colonne dans votre table en sortie appelée RowID, qui contient le numéro de la ligne dans la table, puis utilisez-la pour renseigner les valeurs de données.
=IF( INDIRECT("Table3[RowId]")<=ROWS(Table1)
,INDEX(Table1[column1],INDIRECT("Table3[RowId]"))
,INDEX(Table2[Column1],INDIRECT("Table3[RowId]")-ROWS(Table1)))
Il y a un explication détaillée de la façon dont cela fonctionne sur mon blog car c'était trop long à inclure ici.
J'utilise ce code/formule. fonctionne bien pour mes besoins La seule chose que j'aimerais savoir, c'est comment puis-je créer une meilleure formule de cellule pour pouvoir utiliser 3 tableaux ou plus à titre de référence. actuellement im imbriquant un tas de déclarations iferror au sein de l'iferror
=IFERROR(INDEX(Table1, ROW([@Date])-ROW(Table3[#Headers]),COLUMN(A:A)),IFERROR( INDEX(Table2, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table1),COLUMN(A:A)), IFERROR(INDEX(Table4, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table2)-ROWS(Table1),COLUMN(A:A)),INDEX(Table5, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table2)-ROWS(Table1)-ROWS(Table4),COLUMN(A:A)))))
J'utilise aussi le
Une légère modification du code de Jeeped.
Si vous utilisez une approche similaire, mais avec plusieurs tables (plus de 10 par exemple), il sera alors fastidieux d’essayer d’ajouter manuellement chaque nom de chaque table. Cela pose également un problème si vous modifiez les noms des tables, car ces noms sont câblés dans VBA. Pour éviter tout travail supplémentaire, considérez ceci:
Donc, supposons ce qui suit:
Ensuite, le Workbook_SheetChange Sub de l'exemple ci-dessus pourrait ressembler à ceci:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim tbl As ListObject
For Each tbl In ActiveSheet.ListObjects
If Not Intersect(Target, tbl.Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table
End If
Next tbl
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Modifier. La deuxième routine ressemblera alors à:
Private Sub update_Table()
Dim iTBL3rws As Long, rng As Range, rngOLDBDY As Range
Dim tbl As ListObject
Dim sht As Worksheet
iTBL3rws = 0
' consider all tables, excluding master table
For Each sht In ThisWorkbook.Worksheets
For Each tbl In sht.ListObjects
If tbl.Name <> "Table3" Then
iTBL3rws = iTBL3rws + tbl.DataBodyRange.Rows.Count
End If
Next tbl
Next sht
iTBL3rws = iTBL3rws + Sheet3.ListObjects("Table3").DataBodyRange.Cells(1, 1).Row - Sheet3.ListObjects("Table3").Range.Cells(1, 1).Row
With Sheet3.ListObjects("Table3")
Set rngOLDBDY = .DataBodyRange
.Resize .Range.Cells(1, 1).Resize(iTBL3rws, .DataBodyRange.Columns.Count)
If rngOLDBDY.Rows.Count > .DataBodyRange.Rows.Count Then
For Each rng In rngOLDBDY
If Intersect(rng, .DataBodyRange) Is Nothing Then
rng.Clear
End If
Next rng
End If
End With
End Sub
Cette routine diffère de la précédente en éliminant les cas préprogrammés. Lorsqu'une modification est enregistrée dans une feuille de calcul active, toute table de cette feuille qui est sur le point d'être modifiée déclenchera update_Table procedure.