C# 在内存中合并两个datatable并对它们进行分组以获得列的总和。使用linq但在这里有点丢失
我有两个表,其中两列是固定的。有些列是相同的,有些是新的。列是动态的。 必须在代码级别执行,我正在尝试循环和条件 我想要的是根据条件生成一个报告C# 在内存中合并两个datatable并对它们进行分组以获得列的总和。使用linq但在这里有点丢失,c#,linq,datatable,group-by,C#,Linq,Datatable,Group By,我有两个表,其中两列是固定的。有些列是相同的,有些是新的。列是动态的。 必须在代码级别执行,我正在尝试循环和条件 我想要的是根据条件生成一个报告 表1和表2中的所有列都必须存在 若一个列是公共的,并且有值,那个么它应该和其他表中的相同行一起添加 如果一个表中存在任何行,但另一个表中不存在任何行,则应包括该行 示例数据 表1 ID | NAME | P1 | P2 | P3 ---------------------------- 1 | A1 | 1 | 2 | 3
- 表1和表2中的所有列都必须存在
- 若一个列是公共的,并且有值,那个么它应该和其他表中的相同行一起添加
- 如果一个表中存在任何行,但另一个表中不存在任何行,则应包括该行
ID | NAME | P1 | P2 | P3
----------------------------
1 | A1 | 1 | 2 | 3.3
2 | A2 | 4.4 | 5 | 6
表2
ID | NAME | P1 | P2 | P4
---------------------------
1 | A1 | 10 | 11 | 12
2 | A2 | 12 | 14 | 15
3 | A3 | 16 | 17 | 18
预期产出:
ID | NAME | P1 | P2 | P3 | P4
---------------------------------
1 | A1 | 11 | 13 | 3.3 | 12
2 | A2 | 16.4 | 19 | 6 | 15
3 | A3 | 16 | 17 | null| 18
迄今为止的进展:
首先,我将这两个表合并到表1中
table1.合并(table2)
然后试着在上面分组
var query = from row in table1.AsEnumerable()
group row by new
{
ID = row.Field<int>("ID"),
Name = row.Field<string>("Name")
}
into grp
select new
{
ID = grp.Key.ID,
Name = grp.Key.Name,
Phase1 = grp.Sum(r => r.Field<decimal>("P1"))
};
var query=from表1.AsEnumerable()中的行
按“新建”分组行
{
ID=行字段(“ID”),
名称=行字段(“名称”)
}
玻璃钢
选择新的
{
ID=grp.Key.ID,
Name=grp.Key.Name,
相位1=组和(r=>r字段(“P1”))
};
我修改了这段代码以获得一个数据表请参阅随附的cs文件。这是可行的,但由于列的数量是动态的,我想我必须对其他列重复它,并将所有这些小表连接到将添加一列的位置 我如何合并所有这些小表格 我在这里迷路了,还有别的办法吗。这感觉很愚蠢 任何帮助都将不胜感激 附件:
您希望使用完全外部联接的实现。类似于下面的内容 一些设置,以便您可以自己尝试:
DataTable t1 = new DataTable();
t1.Columns.Add("ID", typeof(int));
t1.Columns.Add("Name", typeof(string));
t1.Columns.Add("P1", typeof(double));
t1.Columns.Add("P2", typeof(double));
t1.Columns.Add("P3", typeof(double));
DataRow dr1 = t1.NewRow();
dr1["ID"] = 1;
dr1["Name"] = "A1";
dr1["P1"] = 1;
dr1["P2"] = 2;
dr1["P3"] = 3.3;
t1.Rows.Add(dr1);
DataRow dr2 = t1.NewRow();
dr2["ID"] = 2;
dr2["Name"] = "A2";
dr2["P1"] = 4.4;
dr2["P2"] = 5;
dr2["P3"] = 6;
t1.Rows.Add(dr2);
DataTable t2 = new DataTable();
t2.Columns.Add("ID", typeof(int));
t2.Columns.Add("Name", typeof(string));
t2.Columns.Add("P1", typeof(double));
t2.Columns.Add("P2", typeof(double));
t2.Columns.Add("P4", typeof(double));
DataRow dr3 = t2.NewRow();
dr3["ID"] = 1;
dr3["Name"] = "A1";
dr3["P1"] = 10;
dr3["P2"] = 11;
dr3["P4"] = 12;
t2.Rows.Add(dr3);
DataRow dr4 = t2.NewRow();
dr4["ID"] = 2;
dr4["Name"] = "A2";
dr4["P1"] = 12;
dr4["P2"] = 14;
dr4["P4"] = 15;
t2.Rows.Add(dr4);
DataRow dr5 = t2.NewRow();
dr5["ID"] = 3;
dr5["Name"] = "A3";
dr5["P1"] = 16;
dr5["P2"] = 17;
dr5["P4"] = 18;
t2.Rows.Add(dr5);
查询如下所示:
var ids = (from r1 in t1.AsEnumerable() select new { ID = r1["ID"], Name = r1["Name"] }).Union(
from r2 in t2.AsEnumerable() select new { ID = r2["ID"], Name = r2["Name"] });
var query = from id in ids
join r1 in t1.AsEnumerable() on id equals new { ID = r1["ID"], Name = r1["Name"] } into left
from r1 in left.DefaultIfEmpty()
join r2 in t2.AsEnumerable() on id equals new { ID = r2["ID"], Name = r2["Name"] } into right
from r2 in right.DefaultIfEmpty()
select new
{
ID = (r1 == null) ? r2["ID"] : r1["ID"],
Name = (r1 == null) ? r2["Name"] : r1["Name"],
P1 = (r1 == null) ? r2["P1"] : (r2["P1"] == null) ? r1["P1"] : (double)r1["P1"] + (double)r2["P1"],
P2 = (r1 == null) ? r2["P2"] : (r2["P2"] == null) ? r1["P2"] : (double)r1["P2"] + (double)r2["P2"],
P3 = (r1 == null) ? null : r1["P3"],
P4 = (r2 == null) ? null : r2["P4"]
};
由于列是动态的,因此需要返回具有动态属性的对象。你可以用一只手来做这件事 下面的代码在很多方面都很难看——我会在放手之前进行一些大规模的重构——但它完成了任务,可能会帮助您实现您想要的。
(很抱歉使用其他linq语法。)
var query=table1.AsEnumerable()
.GroupBy(行=>新建)
{
ID=行字段(“ID”),
名称=行字段(“名称”)
})
.选择(grp=>
{
动态结果=新的ExpandooObject();
var dict=结果为IDictionary;
result.ID=grp.Key.ID;
result.Name=grp.Key.Name;
foreach(grp中的数据行)
{
foreach(表1.Columns中的DataColumn列)
{
字符串columnName=column.columnName;
if(columnName.Equals(“ID”)| | columnName.Equals(“Name”))
继续;
//否则
如果(!dict.Keys.Contains(columnName))
dict[columnName]=行[columnName];
其他的
{
if(行[columnName]为System.DBNull)
继续;
if(dict[columnName]为System.DBNull)
{
dict[columnName]=行[columnName];
继续;
}
//否则
dict[columnName]=(十进制)dict[columnName]+(十进制)行[columnName];
}
}
}
返回结果;
});
通过
table1.Merge(table2, true, MissingSchemaAction.Add);
finalTable = table1.Clone();
finalTable.PrimaryKey = new DataColumn[] { finalTable.Columns["ID"], finalTable.Columns["Name"] };
List<string> columnNames = new List<string>();
for (int colIndex = 2; colIndex < finalTable.Columns.Count; colIndex++)
{
columnNames.Add(finalTable.Columns[colIndex].ColumnName);
}
foreach (string cols in columnNames)
{
var temTable = new DataTable();
temTable.Columns.Add("ID", typeof(int));
temTable.Columns.Add("Name", typeof(string));
temTable.Columns.Add(cols, typeof(decimal));
(from row in table1.AsEnumerable()
group row by new { ID = row.Field<int>("ID"), Team = row.Field<string>("Team") } into grp
orderby grp.Key.ID
select new
{
ID = grp.Key.ID,
Name = grp.Key.Team,
cols = grp.Sum(r => r.Field<decimal?>(cols)),
})
.Aggregate(temTable, (dt, r) => { dt.Rows.Add(r.ID, r.Team, r.cols); return dt; });
finalTable.Merge(temTable, false, MissingSchemaAction.Ignore);
}
table1.Merge(table2,true,MissingSchemaAction.Add);
finalTable=table1.Clone();
finalTable.PrimaryKey=新数据列[]{finalTable.Columns[“ID”],finalTable.Columns[“Name”]};
List columnNames=新列表();
对于(int colIndex=2;colIndexr.Field(cols)),
})
.Aggregate(temTable,(dt,r)=>{dt.Rows.Add(r.ID,r.Team,r.cols);返回dt;});
合并(temTable,false,MissingSchemaAction.Ignore);
}
如果您有动态列,就没有真正干净的解决方案。主要是因为需要动态列通常意味着有更好的方法存储数据。如果操作正确,可能会提供一种更简单的查询所需数据的方法。@Web-E:实际上,您可以使用字典,因此不需要4.0。但是,我看到您已经创建了一个满足您需要的解决方案。:-)
table1.Merge(table2, true, MissingSchemaAction.Add);
finalTable = table1.Clone();
finalTable.PrimaryKey = new DataColumn[] { finalTable.Columns["ID"], finalTable.Columns["Name"] };
List<string> columnNames = new List<string>();
for (int colIndex = 2; colIndex < finalTable.Columns.Count; colIndex++)
{
columnNames.Add(finalTable.Columns[colIndex].ColumnName);
}
foreach (string cols in columnNames)
{
var temTable = new DataTable();
temTable.Columns.Add("ID", typeof(int));
temTable.Columns.Add("Name", typeof(string));
temTable.Columns.Add(cols, typeof(decimal));
(from row in table1.AsEnumerable()
group row by new { ID = row.Field<int>("ID"), Team = row.Field<string>("Team") } into grp
orderby grp.Key.ID
select new
{
ID = grp.Key.ID,
Name = grp.Key.Team,
cols = grp.Sum(r => r.Field<decimal?>(cols)),
})
.Aggregate(temTable, (dt, r) => { dt.Rows.Add(r.ID, r.Team, r.cols); return dt; });
finalTable.Merge(temTable, false, MissingSchemaAction.Ignore);
}