Combinaison de n DataTables dans un seul DataTable

Tous, il y a une question à ce sujet, mais je n’arrive pas à extraire suffisamment d’informations pour résoudre le problème pour mon cas. J’extrais un nombre inconnu de tables dans SQL Server ‘Tab1’, ‘Tab2’, ‘Tab3’, …, ‘TabN’. Les colonnes de ces tables sont différentes, mais les définitions de lignes sont les mêmes. Je dois extraire toutes les données du serveur dans N DataTable , puis les combiner pour former un seul DataTable . Ce que je fais actuellement est

 int nTmpVolTabIdx = 1; strSqlTmp = Ssortingng.Empty; using (DataTable dataTableALL = new DataTable()) { while (true) { ssortingng strTmpVolName = Ssortingng.Format("Tab{0}", nTmpVolTabIdx); strSqlTmp = Ssortingng.Format("SELECT * FROM [{0}];", strTmpVolName); // Pull the data from 'VolX' into a local DataTable. using (DataTable dataTable = UtilsDB.DTFromDB(conn, strTmpVolName, strSqlTmp, false)) { if (dataTable == null) break; else dataTableALL.Merge(dataTable); } nTmpVolTabIdx++; } ... } 

Cela fusionne les DataTable mais ils sont mal alignés (remplissage de cellules vides dans le jeu de données ajouté). Je pourrais append les colonnes du nouveau DataTable via une boucle; mais existe-t-il un moyen plus simple et plus pratique de le faire (en utilisant éventuellement LINQ)?

Merci pour votre temps.

Modifier. Fournir les exemples de jeux de données.

Ce dont j’avais besoin, c’est

Full DataTable

Les tables individuelles sont

Onglets

Après la première opération de fusion, j’ai les éléments suivants

Après la fusion

Merci encore.

La table a des clés primaires répétitives après la Merge car aucune clé primaire n’a été définie. Donc, spécifiez le PK ou essayez cette méthode que j’ai écrite de toutes pièces (donc ce n’est pas vraiment testée) :

 public static DataTable MergeAll(this IList tables, Ssortingng primaryKeyColumn) { if (!tables.Any()) throw new ArgumentException("Tables must not be empty", "tables"); if(primaryKeyColumn != null) foreach(DataTable t in tables) if(!t.Columns.Contains(primaryKeyColumn)) throw new ArgumentException("All tables must have the specified primarykey column " + primaryKeyColumn, "primaryKeyColumn"); if(tables.Count == 1) return tables[0]; DataTable table = new DataTable("TblUnion"); table.BeginLoadData(); // Turns off notifications, index maintenance, and constraints while loading data foreach (DataTable t in tables) { table.Merge(t); // same as table.Merge(t, false, MissingSchemaAction.Add); } table.EndLoadData(); if (primaryKeyColumn != null) { // since we might have no real primary keys defined, the rows now might have repeating fields // so now we're going to "join" these rows ... var pkGroups = table.AsEnumerable() .GroupBy(r => r[primaryKeyColumn]); var dupGroups = pkGroups.Where(g => g.Count() > 1); foreach (var grpDup in dupGroups) { // use first row and modify it DataRow firstRow = grpDup.First(); foreach (DataColumn c in table.Columns) { if (firstRow.IsNull(c)) { DataRow firstNotNullRow = grpDup.Skip(1).FirstOrDefault(r => !r.IsNull(c)); if (firstNotNullRow != null) firstRow[c] = firstNotNullRow[c]; } } // remove all but first row var rowsToRemove = grpDup.Skip(1); foreach(DataRow rowToRemove in rowsToRemove) table.Rows.Remove(rowToRemove); } } return table; } 

Vous pouvez l’appeler de cette façon:

 var tables = new[] { tblA, tblB, tblC }; DataTable TblUnion = tables.MergeAll("c1"); 

Utilisé cet exemple de données:

 var tblA = new DataTable(); tblA.Columns.Add("c1", typeof(int)); tblA.Columns.Add("c2", typeof(int)); tblA.Columns.Add("c3", typeof(ssortingng)); tblA.Columns.Add("c4", typeof(char)); var tblB = new DataTable(); tblB.Columns.Add("c1", typeof(int)); tblB.Columns.Add("c5", typeof(int)); tblB.Columns.Add("c6", typeof(ssortingng)); tblB.Columns.Add("c7", typeof(char)); var tblC = new DataTable(); tblC.Columns.Add("c1", typeof(int)); tblC.Columns.Add("c8", typeof(int)); tblC.Columns.Add("c9", typeof(ssortingng)); tblC.Columns.Add("c10", typeof(char)); tblA.Rows.Add(1, 8500, "abc", 'A'); tblA.Rows.Add(2, 950, "cde", 'B'); tblA.Rows.Add(3, 150, "efg", 'C'); tblA.Rows.Add(4, 850, "ghi", 'D'); tblA.Rows.Add(5, 50, "ijk", 'E'); tblB.Rows.Add(1, 7500, "klm", 'F'); tblB.Rows.Add(2, 900, "mno", 'G'); tblB.Rows.Add(3, 150, "opq", 'H'); tblB.Rows.Add(4, 850, "qrs", 'I'); tblB.Rows.Add(5, 50, "stu", 'J'); tblC.Rows.Add(1, 7500, "uvw", 'K'); tblC.Rows.Add(2, 900, "wxy", 'L'); tblC.Rows.Add(3, 150, "yza", 'M'); tblC.Rows.Add(4, 850, "ABC", 'N'); tblC.Rows.Add(5, 50, "CDE", 'O'); 

Après DataTable.Merge dans MergeAll :

entrez la description de l'image ici

Après quelques modifications pour joindre les lignes dans MergeAll :

entrez la description de l'image ici


Mettre à jour

Puisque cette question est apparue dans l’un des commentaires, si la seule relation entre deux tables est l’index d’un DataRow dans la table et que vous souhaitez fusionner les deux tables en fonction de l’index:

 public static DataTable MergeTablesByIndex(DataTable t1, DataTable t2) { if (t1 == null || t2 == null) throw new ArgumentNullException("t1 or t2", "Both tables must not be null"); DataTable t3 = t1.Clone(); // first add columns from table1 foreach (DataColumn col in t2.Columns) { ssortingng newColumnName = col.ColumnName; int colNum = 1; while (t3.Columns.Contains(newColumnName)) { newColumnName = ssortingng.Format("{0}_{1}", col.ColumnName, ++colNum); } t3.Columns.Add(newColumnName, col.DataType); } var mergedRows = t1.AsEnumerable().Zip(t2.AsEnumerable(), (r1, r2) => r1.ItemArray.Concat(r2.ItemArray).ToArray()); foreach (object[] rowFields in mergedRows) t3.Rows.Add(rowFields); return t3; } 

Échantillon:

 var dt1 = new DataTable(); dt1.Columns.Add("ID", typeof(int)); dt1.Columns.Add("Name", typeof(ssortingng)); dt1.Rows.Add(1, "Jon"); var dt2 = new DataTable(); dt2.Columns.Add("Country", typeof(ssortingng)); dt2.Rows.Add("US"); var dtMerged = MergeTablesByIndex(dt1, dt2); 

La table de résultats contient trois colonnes ID , Name , Country et une seule ligne: 1 Jon US