全外连接,在2个数据表上,带有列列表

我有2个数据表,我不知道他们的数据列列表。 必须在运行时提取此列表,并将其用于完整外部联接。

使用这些列时,需要合并两个表之间的列,并且我需要显示所有数据。

直到现在我正在做的是

  1. 使用intersect获取公共列,并实现IEqualityComparer
  2. 使用这些列创建一个新的数据表,以便将2个数据表合并到此新表中

但是,我在第二步遇到了Linq的问题。

直到现在我有:

获取常见列


     //获取常用列
     var commonColumns = dt1.Columns.OfType()。Intersect(dt2.Columns.OfType(),new DataColumnComparer());

创建新数据表


     //创建将发送给用户的结果
     DataTable结果= new DataTable();

     //添加两个表中的所有列
     result.Columns.AddRange(
     dt1.Columns.OfType()
     .Union(dt2.Columns.OfType(),new DataColumnComparer())
     .Select(c => new DataColumn(c.Caption,c.DataType,c.Expression,c.ColumnMapping))。ToArray());

如何从运行时提取的数据列表中动态获取有效的全外连接?

这可能对你有用

var commonColumns = dt1.Columns.OfType().Intersect(dt2.Columns.OfType(), new DataColumnComparer()); DataTable result = new DataTable(); dt1.PrimaryKey = commonColumns.ToArray(); result.Merge(dt1, false, MissingSchemaAction.AddWithKey); result.Merge(dt2, false, MissingSchemaAction.AddWithKey); 

根据Matthew的回答,我创建了一个接受2个以上数据表的函数。 我希望它有所帮助:

用法:

 var table123 = FullOuterJoinDataTables(table1, table2, table3); 

这是function来源:

 public DataTable FullOuterJoinDataTables(params DataTable[] datatables) // supports as many datatables as you need. { DataTable result = datatables.First().Clone(); var commonColumns = result.Columns.OfType(); foreach (var dt in datatables.Skip(1)) { commonColumns = commonColumns.Intersect(dt.Columns.OfType(), new DataColumnComparer()); } result.PrimaryKey = commonColumns.ToArray(); foreach (var dt in datatables) { result.Merge(dt, false, MissingSchemaAction.AddWithKey); } return result; } /* also create this class */ public class DataColumnComparer : IEqualityComparer { public bool Equals(DataColumn x, DataColumn y) => x.Caption == y.Caption; public int GetHashCode(DataColumn obj) => obj.Caption.GetHashCode(); } 

我也在努力得到答案,我正在复制粘贴整个代码。 我相信这会对你有所帮助。

您只需要DataTable1DataTable2和两个表的主键,在这些表上将执行此连接。 您可以将数据表主键设置为

 datatable1.PrimaryKey = new DataColumn[] { captureDT.Columns["Your Key Name"] }; 

//你的代码

 ///  /// Combines the data of two data table into a single data table. The grouping of tables /// will be based on the primary key provided for both the tables. ///  ///  ///  ///  ///  ///  private DataTable DataTablesOuterJoin(DataTable table1, DataTable table2, string table1PrimaryKey, string table2PrimaryKey) { DataTable flatDataTable = new DataTable(); foreach (DataColumn column in table2.Columns) { flatDataTable.Columns.Add(new DataColumn(column.ToString())); } foreach (DataColumn column in table1.Columns) { flatDataTable.Columns.Add(new DataColumn(column.ToString())); } // Retrun empty table with required columns to generate empty extract if (table1.Rows.Count <= 0 && table2.Rows.Count <= 0) { flatDataTable.Columns.Remove(table2PrimaryKey); return flatDataTable; } var dataBaseTable2 = table2.AsEnumerable(); var groupDataT2toT1 = dataBaseTable2.GroupJoin(table1.AsEnumerable(), br => new { id = br.Field(table2PrimaryKey).Trim().ToLower() }, jr => new { id = jr.Field(table1PrimaryKey).Trim().ToLower() }, (baseRow, joinRow) => joinRow.DefaultIfEmpty() .Select(row => new { flatRow = baseRow.ItemArray.Concat((row == null) ? new object[table1.Columns.Count] : row.ItemArray).ToArray() })).SelectMany(s => s); var dataBaseTable1 = table1.AsEnumerable(); var groupDataT1toT2 = dataBaseTable1.GroupJoin(table2.Select(), br => new { id = br.Field(table1PrimaryKey).Trim().ToLower() }, jr => new { id = jr.Field(table2PrimaryKey).Trim().ToLower() }, (baseRow, joinRow) => joinRow.DefaultIfEmpty() .Select(row => new { flatRow = (row == null) ? new object[table2.Columns.Count].ToArray().Concat(baseRow.ItemArray).ToArray() : row.ItemArray.Concat(baseRow.ItemArray).ToArray() })).SelectMany(s => s); // Get the union of both group data to single set groupDataT2toT1 = groupDataT2toT1.Union(groupDataT1toT2); // Load the grouped data to newly created table foreach (var result in groupDataT2toT1) { flatDataTable.LoadDataRow(result.flatRow, false); } // Get the distinct rows only IEnumerable rows = flatDataTable.Select().Distinct(DataRowComparer.Default); // Create a new distinct table with same structure as flatDataTable DataTable distinctFlatDataTable = flatDataTable.Clone(); distinctFlatDataTable.Rows.Clear(); // Push all the rows into distinct table. // Note: There will be two different columns for primary key1 and primary key2. In grouped rows, // primary key1 or primary key2 can have empty values. So copy all the primary key2 values to // primary key1 only if primary key1 value is empty and then delete the primary key2. So at last // we will get only one perimary key. Please make sure the non-deleted key must be present in foreach (DataRow row in rows) { if (string.IsNullOrEmpty(row[table1PrimaryKey].ToString())) row[table1PrimaryKey] = row[table2PrimaryKey]; if (string.IsNullOrEmpty(row[CaptureBusDateColumn].ToString())) row[CaptureBusDateColumn] = _businessDate; if (string.IsNullOrEmpty(row[CaptureUserIDColumn].ToString())) row[CaptureUserIDColumn] = row[StatsUserIDColumn]; distinctFlatDataTable.ImportRow(row); } // Sort the table based on primary key. DataTable sortedFinaltable = (from orderRow in distinctFlatDataTable.AsEnumerable() orderby orderRow.Field(table1PrimaryKey) select orderRow).CopyToDataTable(); // Remove primary key2 as we have already copied it to primary key1 sortedFinaltable.Columns.Remove(table2PrimaryKey); return ReplaceNulls(sortedFinaltable, "0"); } ///  /// Replace all the null values from data table with specified string ///  ///  ///  ///  private DataTable ReplaceNulls(DataTable dt, string replaceStr) { for (int a = 0; a < dt.Rows.Count; a++) { for (int i = 0; i < dt.Columns.Count; i++) { if (dt.Rows[a][i] == DBNull.Value) { dt.Rows[a][i] = replaceStr; } } } return dt; }