如何在c#中使用公共列实现2个或多个数据表的完全外连接
本文关键字:数据表 连接 2个 实现 | 更新日期: 2023-09-27 18:02:57
我需要用一个公共列合并/连接c#上的数据表。
我知道许多关于同一主题的例子和问题。但是我还没有找到任何能回答我问题的。
下面是我正在使用的代码。
代码只允许基于一个数据表的数据的一个公共列。我需要一个公共列,但它需要考虑在另一个数据表中可能使用的任何其他"Account#",并将其添加到公共列中。
代码也只允许合并两个数据表。我需要合并31个数据表,每个月的每一天合并1个数据表。
我有一个数据表,每个月的每一天,dt_docDAY01, dt_docDAY02, dt_docDAY03等。
每个数据表包含一个帐号"account #"和一个存储在指向日期"DAY01"、"DAY02"等列中的余额。
你能告诉我如何更改代码,以便我将包括所有表中的所有帐户吗?
还有,我将如何合并这段代码中的所有数据表,所以我不必运行相同的代码31次。
'string id = "Account#";
var tableJoinedDAY02 = dt_docDAY01_GROUPED.Clone(); // create columns from table1
// add columns from table2 except id
foreach (DataColumn column in dt_docDAY02_GROUPED.Columns)
{
if (column.ColumnName != id)
tableJoinedDAY02.Columns.Add(column.ColumnName, column.DataType);
}
tableJoinedDAY02.BeginLoadData();
foreach (DataRow row1 in dt_docDAY01_GROUPED.Rows)
{
foreach (DataRow row2 in dt_docDAY02_GROUPED.Rows)
{
if (row1.Field<string>(id) == row2.Field<string>(id))
{
var list = row1.ItemArray.ToList(); // items from table1
// add items from table2 except id
foreach (DataColumn column in dt_docDAY02_GROUPED.Columns)
if (column.ColumnName != id)
list.Add(row2[column]);
tableJoinedDAY02.Rows.Add(list.ToArray());
}
}
}
tableJoinedDAY02.EndLoadData();`
Table1
<>之前账号# | Day011234 | 114567 | 220909 | 33之前表<>之前账号# | Day021234 | 12[0909] [qh5578 | 990065 | 34之前
Table3
<>之前账号# | Day031234 | 137777 | 44之前预期结果合并表
Table1
<>之前帐户# | Day01 | Day02 | Day031234 | 11 | 12 | 134567 | 22 | 0 | 00909 | 33 | 34 | 05578 | 0 | 99 | 00065 | 0 | 34 | 07777 | 0 | 0 | 44@Infost,你正试图做什么在SQL语言是一个full outer join
。在SO上搜索指向这个答案https://stackoverflow.com/a/16832096/97471,我已经适应了超过2个表:
从像这样的MVCE开始:
DataTable table1 = new DataTable();
table1.Columns.Add("Account", typeof(int));
table1.Columns.Add("Day01", typeof(decimal));
table1.Rows.Add(1234, 11);
table1.Rows.Add(4567, 22);
table1.Rows.Add(0909, 33);
DataTable table2 = new DataTable();
table2.Columns.Add("Account", typeof(int));
table2.Columns.Add("Day02", typeof(decimal));
table2.Rows.Add(1234, 12);
table2.Rows.Add(0909, 34);
table2.Rows.Add(5578, 99);
table2.Rows.Add(0065, 34);
DataTable table3 = new DataTable();
table3.Columns.Add("Account", typeof(int));
table3.Columns.Add("Day03", typeof(decimal));
table3.Rows.Add(1234, 13);
table3.Rows.Add(7777, 44);
您可以调用以下函数将它们连接起来:
var table123 = FullOuterJoinDataTables(table1, table2, table3);
函数来源:
DataTable FullOuterJoinDataTables(params DataTable[] datatables) // supports as many datatables as you need.
{
DataTable result = datatables.First().Clone();
var commonColumns = result.Columns.OfType<DataColumn>();
foreach (var dt in datatables.Skip(1))
{
commonColumns = commonColumns.Intersect(dt.Columns.OfType<DataColumn>(), 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<DataColumn>
{
public bool Equals(DataColumn x, DataColumn y) { return x.Caption == y.Caption; }
public int GetHashCode(DataColumn obj) { return obj.Caption.GetHashCode(); }
}
输出为
<>之前帐户Day01 Day02 Day031234 11 12 134567年22日909 33 345578年 99年65年 347777年 44这需要按如下方式处理,所有的表不能通过魔法连接在一起,让我们取一个较小的样本集:
- 表1 (dt1) - Account# | Day01
- 表2 (dt2) - Account# | Day02
- 表3 (dt3) - Account# | Day03
- 表4 (dt4) - Account# | Day04
dt1.AsEnumerable()
.Join(dt2.AsEnumerable(), d1 => (int)d1["Account#"], d2 =>
(int)d2["Account#"],
(d1,d2) => new {Account = (int)d1["Account#"],Day01 =
d1["Day01"],Day02 = d2["Day02"]})
.Join(dt3.AsEnumerable(), d12 => d12.Account, d3 => (int)d3["Account#"],
(d12,d3) => new {d12.Account,d12.Day01,d12.Day02,Day03=d3["Day03"]})
.Join(dt4.AsEnumerable(), dAll => dAll.Account, d4 =>
(int)d4["Account#"],
(dAll,d4) => new
{dAll.Account,dAll.Day01,dAll.Day02,dAll.Day03,Day04=d4["Day04"]})
上述操作的结果将是IEnumerable<AnonymousType>
,其中到目前为止,匿名类型由属性Account,Day01,Day02,Day03,Day04
组成,类似地,您可以添加到Day31
。还要注意,在第一次join之后,我们如何开始使用作为最后一个Join
语句的一部分生成的AnonymousType
这需要转换为DataTable
,这将类似于下面线程中发布的代码:
将IEnumerable转换为DataTable
也检查它的转换为DataTable using IEnumerable of Anonymous type
,使用Nuget实用程序Fastmember