Unión externa completa, en 2 tablas de datos, con una lista de columnas

Tengo 2 tablas de datos, que no sé su lista de columnas de datos. Esta lista debe extraerse en tiempo de ejecución y usarse para la unión externa completa.

Al usar estas columnas, las columnas entre las 2 tablas deben combinarse, y necesito que se muestren todos los datos.

Hasta ahora lo que estoy haciendo es

  1. Obtenga columnas comunes, utilizando intersect, e implementando IEqualityComparer
  2. Cree una nueva tabla de datos, con estas columnas, para que las 2 tablas de datos se fusionen en esta nueva tabla.

Sin embargo, estoy teniendo problemas con Linq, en el segundo paso.

Hasta ahora tengo:

Obtener columnas comunes


     // Obtener columnas comunes
     var commonColumns = dt1.Columns.OfType (). Intersect (dt2.Columns.OfType (), nuevo DataColumnComparer ());

Crear nueva tabla de datos


     // Crea el resultado que será enviado al usuario.
     Resultado de la tabla de datos = nueva tabla de datos ();

     // Añadir todas las columnas de ambas tablas
     result.Columns.AddRange (
     dt1.Columns.OfType ()
     .Union (dt2.Columns.OfType (), nuevo DataColumnComparer ())
     .Seleccione (c => nuevo DataColumn (c.Caption, c.DataType, c.Expression, c.ColumnMapping)). ToArray ());

¿Cómo puedo obtener una combinación externa completa eficiente de la Lista de columnas de datos, que se extrae en tiempo de ejecución?

Esto podría funcionar para usted

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); 

Basado en la respuesta de Matthew, he creado una función que acepta más de 2 datos. Espero que ayude:

Uso:

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

Aquí está la fuente de la función:

 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(); } 

Luché también para obtener la respuesta, estoy copiando y pegando todo el código. Estoy seguro de que esto te ayudará.

solo necesita DataTable1 , DataTable2 y las primarykeys de ambas tablas en las que se realizará esta unión. Puede establecer la clave primaria de datos como

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

// Tu codigo

 ///  /// 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; }