加入2个包含许多列的DataTables

我有一个问题,想要加入2个同一列的表。 表1包含Name,LastName Columns和许多其他列,表2包含Name,Comment和许多其他列。 我想用Name列加入它们,结果应该是Name,LastName,Comment和其他列。 我尝试使用左外侧Linq,但不知道如何编写select new,因为我不知道我有多少其他列。

我的表1:

Name1 LastName ... Niki Row ... Hube Slang ... Koke Mi ... ... ... ... ... ... ... 

表2:

 Name Comment ... Koke "Hello" ... Niki "Hi" ... 

结果应该是:

 Name LastName Comment ... Niki Row "Hi" ... Hube Sland ... Koke Mi "Hello"... ... ... ... 

所以我试着将这些行连在一起。 但是它说table1中的数组比表2中的数组长。有没有其他方法可以加入它?

  foreach (DataRow tbE in Table1.Rows) { foreach (DataRow opT in Table2.Rows) { if (tbE["Name"].ToString() == opT["Name"].ToString()) { var row = Result.NewRow(); row.ItemArray = tbE.ItemArray .Concat(opT.ItemArray).ToArray(); Result.Rows.Add(row); } else Result.ImportRow(tbE); } } Result.Columns.Remove(Name); 

你可以在这里使用这个方法,我最近从头开始写了另一个问题的 SO(所以它没有经过实际测试)。 它允许通过公共密钥合并多个表。 如果没有指定密钥,它将只使用默认的DataTable.Merge方法:

 public static DataTable MergeAll(this IList tables, String 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; } 

你可以用这种方式调用它:

 var tables = new[] { Table1, Table2 }; tables.MergeAll("Name"); 

编辑 :这是调试器与您的示例数据的屏幕截图:

在此处输入图像描述

所以它有效:)

示例数据和测试:

 var Table1 = new DataTable(); var Table2 = new DataTable(); Table1.Columns.Add("Name"); Table1.Columns.Add("LastName"); Table2.Columns.Add("Name"); Table2.Columns.Add("Comment"); Table1.Rows.Add("Niki", "Row"); Table1.Rows.Add("Hube", "Slang"); Table1.Rows.Add("Koke", "Mi"); Table2.Rows.Add("Koke", "Hello"); Table2.Rows.Add("Niki", "Hi"); var tables = new DataTable[] { Table1, Table2 }; DataTable merged = tables.MergeAll("Name"); 

这是我的一点贡献。 此部分代码可用于在指定的列名称上连接任意两个DataTable。 (您不需要知道其余列)以下是一些function:

  1. 结果DataTable不会有用于连接的重复列。 例如,如果您加入“名称”列,则最后只有一个“名称”列,而不是每个表中的一个副本。
  2. 如果重复列未在连接中使用,则第二个表中的重复列将通过在末尾附加“_2”来重命名。 它可以以其他方式运行,只需更改代码的那一部分。
  3. 支持多个Join列。 为此,创建了一个JoinKey类,使它们可以被LINQ比较。
  4. 这段代码是我在网上找到的代码和我的试错的混合物。 我是LINQ的新手,所以请随意批评〜

     public class JoinKey { List objects { get; set; } public JoinKey(List objects) { this.objects = objects; } public override bool Equals(object obj) { if (obj == null || obj.GetType() != typeof(JoinKey)) return false; return objects.SequenceEqual(((JoinKey)obj).objects); } public override int GetHashCode() { int hash = 0; foreach (var foo in objects) { hash = hash * 31 + foo.GetHashCode(); } return hash; } } public enum JoinType { Inner = 0, Left = 1 } //Joins two tables and spits out the joined new DataTable. Tables are joined on onCol column names //If the right table has column name clashes with the left column, the column names will be appended "_2" and added to joined table public static DataTable Join(DataTable left, DataTable right, JoinType joinType, params string[] onCol) { Func getKey = (row) => { return new JoinKey(onCol.Select(str => row[str]).ToList()); }; var dt = new DataTable(left.TableName); var colNumbersToRemove = new List(); //Populate the columns foreach (DataColumn col in left.Columns) { if (dt.Columns[col.ColumnName] == null) dt.Columns.Add(new DataColumn(col.ColumnName, col.DataType, col.Expression, col.ColumnMapping)); } for (int colIdx = 0; colIdx < right.Columns.Count; ++colIdx) { var col = right.Columns[colIdx]; //if this is joined column, it will be removed. if (onCol.Contains(col.ColumnName)) { colNumbersToRemove.Add(colIdx); } else { //if this is duplicate column, it will be renamed. if (dt.Columns[col.ColumnName] != null) { col.ColumnName += "_2"; } dt.Columns.Add(new DataColumn(col.ColumnName, col.DataType, col.Expression, col.ColumnMapping)); } } if (joinType == JoinType.Left) { var res = from l in left.AsEnumerable() join r in right.AsEnumerable() on getKey(l) equals getKey(r) into temp from r in temp.DefaultIfEmpty() select l.ItemArray.Concat(((r == null) ? (right.NewRow().ItemArray) : r.ItemArray).Minus(colNumbersToRemove)).ToArray(); foreach (object[] values in res) dt.Rows.Add(values); } else { //Inner Join var res = from l in left.AsEnumerable() join r in right.AsEnumerable() on getKey(l) equals getKey(r) into temp from r in temp select l.ItemArray.Concat(((r == null) ? (right.NewRow().ItemArray) : r.ItemArray).Minus(colNumbersToRemove)).ToArray(); foreach (object[] values in res) dt.Rows.Add(values); } return dt; }