Comment fusionner deux tableaux dans Excel qui ont des colonnes identiques?

11

Dans Excel, j'ai une feuille de calcul qui extrait les données d'une base de données SQL dans une table, puis génère un rapport basé sur ces données. Malheureusement, les données de cette base de données SQL sont incomplètes et je souhaite inclure des lignes supplémentaires dans le jeu de résultats qui sont entrées manuellement dans la feuille de calcul.

Autant que je voudrais, je ne peux pas simplement insérer manuellement ces lignes supplémentaires dans le tableau car elles seraient supprimées chaque fois qu'Excel extrait de nouvelles données de la base de données SQL. Donc, à la place, j'envisage de créer une table distincte avec les mêmes en-têtes de colonne sur une nouvelle feuille et d'y entrer les données, puis de créer une troisième table sur une autre feuille qui combine en quelque sorte les lignes de la table qui extrait les données de SQL et de la table où j'entre les données manuellement. Comment puis-je accomplir cela? (Ou alternativement, y a-t-il une meilleure façon de faire cela qui me manque en quelque sorte?)


Exemple:

Table 1 (From Database):

  | Person | Week Of | Task | Hours |
  | Bob    | 1/6/13  | Foo  | 12    |
  | Mary   | 1/6/13  | Foo  | 7     |
  | Mary   | 1/6/13  | Bar  | 5     |
  | John   | 1/6/13  | Foo  | 5     |
  | John   | 1/13/13 | Foo  | 13    |

-

Table 2 (Entered Manually): 
  | Person | Week Of | Task | Hours |
  | Bob    | 1/6/13  | Baz  | 3     |
  | Mary   | 1/6/13  | Baz  | 2     |
  | John   | 1/13/13 | Baz  | 5     |

-

Result:
  | Person | Week Of | Task | Hours |
  | Bob    | 1/6/13  | Foo  | 12    |
  | Mary   | 1/6/13  | Foo  | 7     |
  | Mary   | 1/6/13  | Bar  | 5     |
  | John   | 1/6/13  | Foo  | 5     |
  | John   | 1/13/13 | Foo  | 13    |
  | Bob    | 1/6/13  | Baz  | 3     |
  | Mary   | 1/6/13  | Baz  | 2     |
  | John   | 1/13/13 | Baz  | 5     |
Ajedi32
la source
Cela vous convient-il si vos données ajoutées manuellement sont inférieures à vos données SQL? Ou doivent-ils être triés par date. Excel ne remplacera pas les lignes situées juste en dessous des lignes de données SQL existantes. Mais si les deux types de données doivent être triés, le tout est plus compliqué.
nixda
Eh bien, je préférerais qu'ils soient triés, mais ce n'est pas complètement nécessaire. L'important est que je puisse utiliser des tableaux croisés dynamiques et d'autres outils Excel pour analyser l'ensemble des données (y compris les tableaux remplis manuellement et automatiquement). Je dois également pouvoir continuer à extraire automatiquement de nouvelles données de SQL.
Ajedi32
Ce comportement serait-il une solution? Après la première requête et après la deuxième requête . Et bien sûr, Excel mettra automatiquement à jour votre SQL lorsque vous ouvrirez le classeur.
nixda
Cela fonctionnerait, je suppose. Je préfère avoir les données dans une seule table afin de pouvoir filtrer, trier, etc., mais comme je l'ai déjà dit, ce n'est pas entièrement nécessaire.
Ajedi32
nous trouverons peut-être une solution à votre problème de tri. Mais pour la première étape, interrogez simplement votre SQL pour la première fois dans un nouveau classeur. Après cela, ajoutez vos entrées manuelles juste en dessous. Maintenant, testez-le avec une deuxième requête (et plus). Ils ne seront pas écrasés. C'est un comportement standard. Il n'y a rien de spécial à faire.
nixda

Réponses:

2

Voici une solution Excel pure sans VBA. Il fonctionne en utilisant une fonction INDEX pour descendre les lignes et les colonnes des données SQL jusqu'à ce que les valeurs soient épuisées et qu'une condition d'erreur se produise. Une fonction IFERROR intercepte l'erreur et utilise une deuxième fonction INDEX pour descendre les lignes et les colonnes des données saisies manuellement, jusqu'à ce que ces valeurs soient épuisées et qu'une condition d'erreur se produise. Une deuxième fonction IFERROR intercepte l'erreur et renvoie un tiret ("-"). (Les données SQL doivent être actualisées via le ruban pour que les formules produisent un résultat correct.)

Créez une plage nommée dynamique SQLDB pour les données SQL de la feuille Sheet1 à l'aide de la formule:

=OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A)-1,COUNTA(Sheet1!$1:$1))

Créez une deuxième plage nommée dynamique EXCELRNG pour les données saisies manuellement dans la feuille Sheet2 à l'aide de la formule:

=OFFSET(Sheet2!$A$1,1,0,COUNTA(Sheet2!$A:$A)-1,COUNTA(Sheet2!$1:$1))

Ces deux plages nommées supposent que les noms de variables sont entrés dans la ligne 1 de chacune des deux feuilles.

Entrez les noms des variables dans la ligne 1 de la feuille Sheet3 (commençant dans la cellule A1).

Entrez la formule suivante dans la cellule A2 de la feuille Sheet3:

=IFERROR(INDEX(SQLDB,ROWS(A$2:A2),COLUMN(A2)),IFERROR(INDEX(EXCELRNG,ROWS(A$2:A2)-ROWS(SQLDB),COLUMN(A2)),"-"))

Copiez la formule dans les colonnes de nom de variable, puis descendez les lignes jusqu'à ce que les résultats des formules soient tous des tirets ("-").

Il est possible dans une prochaine étape de créer un tableau croisé dynamique dans une autre feuille pour l'analyse et l'organisation.

Encore une fois, la première étape consiste à créer une plage nommée dynamique, disons RESULTRNG, en insérant la formule suivante dans la zone de saisie Gestionnaire de noms pour la plage nommée:

=OFFSET(Sheet3!$A$1,0,0,COUNTA(Sheet1!$A:$A)+COUNTA(Sheet2!$A:$A)-1,COUNTA(Sheet1!$1:$1))

Créez ensuite un tableau croisé dynamique dans une nouvelle feuille, en définissant RESULTRNG comme tableau que vous souhaitez analyser. Cela filtrera tous les tirets de fin du tableau de formule dans la feuille Sheet3.

Cela fonctionne car la formule RESULTRNG compte le nombre total de lignes dans Sheet1 et Sheet2 (à l'exclusion de l'en-tête dans Sheet2) et le nombre total de colonnes dans Sheet1, et définit son étendue en fonction de ces nombres, à l'exclusion des tirets dans les lignes de fin ( ou colonnes) dans la table de formule Sheet3.

chuff
la source
Si je le faisais de cette façon, la table combinée ne devrait-elle pas avoir une taille fixe? Et si la table était plus grande que nécessaire, cela ne me gâcherait-il pas si j'essayais de créer un tableau croisé dynamique qui gère les données de la table combinée? (Parce que certaines des valeurs du tableau seraient des caractères «-»?) Ou existe-t-il un moyen de contourner ces problèmes?
Ajedi32
(Btw, je préfère généralement les solutions Excel pures comme celle-ci car elles ne nécessitent pas que l'utilisateur active les macros avant de commencer à travailler.)
Ajedi32
Cela nécessiterait une maintenance manuelle pour s'assurer que les formules capturaient toutes les données dans les deux tableaux. Pour éviter les tirets, vous devez copier les formules uniquement là où elles ont renvoyé les données, pas les tirets.
chuff
Serait-il possible de créer une autre plage nommée qui comprend uniquement les lignes de la table fusionnée qui ne sont pas vides (remplies de caractères «-»)? De cette façon, je pouvais simplement définir les tableaux croisés dynamiques pour obtenir leurs données de cette plage et je n'aurais pas à me soucier des tirets.
Ajedi32
J'ai développé ma réponse pour expliquer comment vous pouvez créer un tableau croisé dynamique en excluant les tirets. Essayer de mettre un tableau "sans tiret" ne ferait que transférer le problème du tiret vers une autre feuille, avec # N / A dans les cellules du tiret à moins que le nouveau tableau ne soit dimensionné à la main chaque fois que le nombre de lignes dans les données source change.
chuff
5

J'ai trouvé un moyen de le faire. Cette solution est un peu délicate et nécessite que les deux tables aient leurs propres feuilles séparées (sans rien d'autre), mais à part cela, elle fait presque exactement ce que je veux. (Il semble également y avoir beaucoup de potentiel pour effectuer des opérations plus complexes telles que les jointures.)

Accédez à l'onglet de données sur le ruban, cliquez sur "À partir d'autres sources" et "À partir de Microsoft Query". Cliquez ensuite sur Fichiers Excel, sélectionnez le fichier dans lequel vous travaillez actuellement et cliquez sur OK. Ensuite, appuyez sur Annuler et lorsque vous êtes promu si vous souhaitez continuer la modification dans Microsoft Query, cliquez sur "Oui". À partir de là, vous pouvez cliquer sur le bouton SQL et écrire une requête SQL personnalisée sur n'importe quelle feuille de la feuille de calcul. Dans mon cas:

SELECT *
FROM `'Sheet1$'` `'Sheet1$'`
UNION ALL
SELECT *
FROM `'Sheet2$'` `'Sheet2$'`

Remarque: Pour moi, cette méthode cesse de fonctionner après avoir fermé le fichier et l'ouvrir à nouveau. Je le poste ici de toute façon, même si c'est juste un problème avec mon ordinateur ou si quelqu'un d'autre peut le faire fonctionner.

Ajedi32
la source
1
Cela fonctionne bien en connectant deux classeurs différents. C'était exactement ce dont j'avais besoin. Je vous remercie!
daVe
Cette méthode fonctionne très bien pour moi. Exécutez la requête, puis copiez simplement les données et collez-les dans Excel. Cependant, il est important de noter que cela supprimera toutes les lignes en double de vos données, j'espère que cela ne vous dérange pas si je modifie un peu cette réponse.
Some_Guy
Ajouter parce que cela m'est réellement arrivé, j'ai presque utilisé cela pour fusionner un tas de données de vente dans une feuille de calcul avant de faire un pivot pour obtenir des totaux, et j'aurais eu quelques erreurs où le même volume d'un produit vendu plusieurs fois aurait été raté.
Some_Guy
@Some_Guy Utilisez simplement UNION ALL à la place.
Ajedi32
3

Si vous êtes intéressé par une solution VBA, j'ai pu faire fonctionner les éléments suivants:

  • Définissez une plage nommée dynamique pour les données que vous extrayez de SQL Server. Ouvrez le gestionnaire de noms, entrez un nouveau nom (par exemple, "SQLDB") et copiez la formule suivante dans la zone de saisie Fait référence à. J'ai supposé que vos données récupérées se trouvent dans la feuille Sheet1:

    =OFFSET(Sheet1!$A$1,0,0,COUNTA(Sheet1!$A:$A),COUNTA(Sheet1!$1:$1))
    
  • Définissez une autre plage nommée pour la plage dans laquelle les données manuelles sont entrées. J'ai utilisé le nom EXCELRNG et j'ai supposé que c'était dans Sheet2. La plage nommée commence à la ligne 2 pour exclure une ligne d'en-tête. La formule ici est identique à la première sauf pour la feuille à laquelle elle se réfère:

    =OFFSET(Sheet2!$A$1,1,0,COUNTA(Sheet2!$A:$A)-1,COUNTA(Sheet2!$1:$1))
    
  • Voici le premier ensemble de paramètres que j'ai utilisé pour la connexion à la table SQL. La boîte de dialogue est accessible en sélectionnant Connexions dans l'onglet Données du ruban. La désactivation de l'actualisation en arrière-plan garantit que la macro VBA se met en pause jusqu'à ce qu'une actualisation des données dans la feuille Excel soit terminée. Il peut ne pas être nécessaire d'actualiser la connexion lorsque la feuille de calcul s'ouvre, mais je voulais m'assurer que toute authentification serait effectuée avant l'exécution de la macro.

paramètres de connexion

  • Voici le deuxième ensemble de paramètres. Ceux-ci se trouvent dans la section Propriétés de l'onglet Données (lorsqu'une cellule du tableau SQL importé est sélectionnée). Bien que j'aie choisi l'option "Insérer des lignes entières pour les nouvelles données, supprimer les cellules inutilisées", je n'ai en fait rencontré aucun problème avec l'option "Insérer les cellules ...".

propriétés de connexion

  • Enfin, c'est le code VBA. Pour l'insérer, choisissez Visual Basic sous l'onglet Développeur. Mettez en surbrillance le nom de la feuille de calcul dans la liste de gauche. Il sera référencé comme "Projet VBA (nom de la feuille). Ensuite, choisissez Insérer un module dans la barre de menus en haut de l'écran et collez le code dans le nouveau module. Notez que j'ai mis la table consolidée dans la feuille Sheet3. Comme écrit, la macro ne trie pas la nouvelle table, bien que cela ne soit pas difficile à ajouter.

    Sub StackTables()
    
       Dim Rng1 As Range, Rng2 As Range
    
       Set Rng1 = ThisWorkbook.Names("SQLDB").RefersToRange
       Set Rng2 = ThisWorkbook.Names("EXCELRNG").RefersToRange
    
       ' refresh the SQL table
       ThisWorkbook.Connections(1).Refresh
    
       ' clear the consolidated table range  
       Sheet3.Cells.ClearContents
    
       ' copy the SQL data into the consolidation range
       Rng1.Copy
       Sheet3.Range("A1").PasteSpecial xlPasteValues
    
       'copy the manually entered data into the consolidate range
       Rng2.Copy
       Sheet3.Range("A1").Offset(Rng1.Rows.Count, 0).PasteSpecial xlPasteValues
       Application.CutCopyMode = False
    
       Sheets("Sheet3").Activate
       ActiveSheet.Range("A1").Select
    
    End Sub
    
chuff
la source
Cela ressemble à une solution assez solide. J'ai cependant quelques questions. Qu'est-ce qui déclenche cette macro? Il s'exécute automatiquement lorsque vous actualisez les connexions de données, ou devez-vous appuyer sur un bouton distinct pour l'exécuter manuellement? Deuxièmement, cela fonctionne avec des tables non? (Pas seulement des plages qui ne sont pas formatées sous forme de tableaux) Si tel est le cas, le tableau lui-même ne peut-il pas gérer le tri? (Au lieu que la macro VBA fasse le tri, comme vous l'avez suggéré?)
Ajedi32
1
En l'état, vous exécutez la macro en sélectionnant Macros dans l'onglet Développeur, puis en sélectionnant et en exécutant la macro. Deux alternatives: affectez-le à un bouton personnalisé sur le ruban et utilisez-le pour l'exécuter; ou l'incorporer en tant que code macro dans un événement Worksheet_Activate. Cela l'exécuterait chaque fois que vous sélectionnez la feuille de consolidation. Cela fonctionnera avec des tables, qui peuvent faire le tri. Cependant, je ne suis pas sûr que les tables recourent automatiquement lorsque des données sont ajoutées.
chuff
3

Voici une version de la solution "Pure Excel" de @ chuff conçue spécifiquement pour fonctionner avec des tableaux. (IE Les deux sources de données que vous souhaitez fusionner sont des tableaux.)

La principale différence entre cette méthode et le chuff publié dans sa réponse est que vous n'avez pas besoin de définir de plages nommées pour les deux ensembles de données que vous fusionnez, car ce sont des tables et ont déjà leur propre plage nommée. Alors allez-y et nommez votre première table Table1et votre deuxième table Table2.

Maintenant, créez un nouveau tableau dans le coin supérieur gauche d'une nouvelle feuille et donnez-lui les mêmes noms de colonne que les deux autres tableaux. Entrez ensuite la formule suivante dans la cellule A2 de la feuille que vous venez de créer:

=IFERROR(INDEX(Table1,ROWS(A$2:A2),COLUMN(A2)), IFERROR(INDEX(Table2,ROWS(A$2:A2)-ROWS(Table1),COLUMN(A2)), "-"))

Ensuite, copiez cette formule dans toutes les colonnes du tableau, puis descendez les lignes jusqu'à ce que les résultats des formules soient tous des tirets ("-"). Remarque: Le tri de ce nouveau tableau ne fera rien, car le contenu de chaque cellule est en fait identique (ils contiennent tous la même formule).

Si les colonnes du tableau fusionné affichent des 0 alors qu'elles devraient afficher une cellule vide, vous pouvez encapsuler la formule dans cette colonne avec la fonction de substitution, comme ceci:

=SUBSTITUTE(<old expression here>, 0, "")

Si vous souhaitez créer un tableau croisé dynamique qui utilise les données de ce nouveau tableau, vous devrez créer une plage nommée. Tout d'abord, nommez la table Table3. Maintenant, allez dans l'onglet formules et cliquez sur "Définir le nom". Donnez un nom à la référence, entrez l'équation suivante pour sa valeur ("Fait référence à"):

=OFFSET(Table3[#All],0,0,ROWS(Table1)+ROWS(Table2)+1)

Vous pouvez ensuite utiliser cette référence nommée comme plage pour votre tableau croisé dynamique.

Ajedi32
la source
0

Si vous voulez juste un résultat sur une base unique, il existe un site Web qui fusionnera deux tables pour vous: https://office-tools.online/table/merge/

Vous collez les tableaux dans la page Web et sélectionnez les paramètres appropriés. Voici une capture d'écran de l'exemple intégré qui indique comment l'utiliser:

entrez la description de l'image ici

Hvg Hng
la source