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
Les tables individuelles sont
Après la première opération de fusion, j’ai les éléments suivants
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
:
Après quelques modifications pour joindre les lignes dans MergeAll
:
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