First, you can create a target table, add its columns (summing the number of columns in all input tables), and then add them to the rows, combining separate arrays of values ββfor each row in the input tables.
Of course, the rows in the resulting DataTable will contain values ββsince they are displayed in a top-down direction for each input table (aligned on top). It also means that the number of resulting rows is the number of rows in the largest input table.
First, we initialize and populate the List<DataTable> variable, then we will make the connection using this variable as a method parameter:
#region table collection initialization List<DataTable> dts = new List<DataTable>(); var dt = new DataTable(); dt.Columns.Add("Test0", typeof(string)); dt.Rows.Add(1); dt.Rows.Add(2); dts.Add(dt); dt = new DataTable(); dt.Columns.Add("Test1", typeof(int)); dt.Rows.Add(2); dts.Add(dt); dt = new DataTable(); dt.Columns.Add("Test3", typeof(int)); dt.Columns.Add("Test4"); dt.Columns.Add("Test5", typeof(int)); dt.Rows.Add(3, "a", 1); dt.Rows.Add(4); dt.Rows.Add(5, "a"); dt.Rows.Add(null, "a"); dts.Add(dt); dt = new DataTable(); dt.Columns.Add("Test6", typeof(DateTime)); dt.Columns.Add("Test7", typeof(int)); dt.Rows.Add(DateTime.Now); dts.Add(dt); #endregion // sample method usage var result = GetJoinedTable(dts);
Create a GetJoinedTable method that returns the resulting joined table into the result variable:
private DataTable GetJoinedTable(List<DataTable> dts) { var dest = new DataTable(); //will be used if you have non-unique column names int counter = 0; foreach (var column in dts .SelectMany<DataTable, DataColumn>(t => t.Columns.Cast<DataColumn>())) { dest.Columns.Add(column.ColumnName, column.DataType); // if you have non-unique column names use the following instead //dest.Columns.Add(String.Format("column_{0}", counter++), // column.DataType); } List<object> rowItems; for (int i = 0; i < dts.Max(t => t.Rows.Count); i++) { rowItems = new List<object>(); for (int j = 0; j < dts.Count; j++) { if (dts[j].Rows.Count > i) { var r = dts[j].Rows[i].ItemArray .Select((v, index) => (v == null || v == System.DBNull.Value) ? GetDefault(dts[j].Columns[index].DataType) : v); rowItems.AddRange(r); } else { for (int c = 0; c < dts[j].Columns.Count; c++) { rowItems.Add(GetDefault(dts[j].Columns[c].DataType)); } } } dest.Rows.Add(rowItems.ToArray()); } return dest; }
You will also need to add the following method, which returns the corresponding default column value, based on the DataType property of the column:
object GetDefault(Type t) { if (t.IsValueType) { return Activator.CreateInstance(t); } else { return null; } }