当多列中的数据匹配时,如何合并DataTable中的行?

我试图找出一种在column1,column2,column3,column4匹配时合并DataTable中的行的好方法。 有没有人有关于如何在VB.NET和/或C#中实现这一点的指针或想法?

DataTable with duplicate rows to merge ------------------------------------------------------------- | Column1 | Column2 | Column3 | Column4 | Column5 | Column6 | ------------------------------------------------------------- | 123456 | 6 | 54 | 5 | 0.00 | 36.78 | | 123456 | 6 | 54 | 5 | 21.00 | 0.00 | | 123456 | 6 | 54 | 8 | 0.00 | 102.09 | | 123456 | 6 | 54 | 8 | 6.50 | 0.00 | Final DataTable with merged rows ------------------------------------------------------------- | Column1 | Column2 | Column3 | Column4 | Column5 | Column6 | ------------------------------------------------------------- | 123456 | 6 | 54 | 5 | 21.00 | 36.78 | | 123456 | 6 | 54 | 8 | 6.50 | 102.09 | 

这是一个非LINQ替代方案。 它的作用是迭代第一个表中的每一行。 然后它检查辅助表以查看其中是否有符合条件的行。 如果有,则在其他列中添加值。 如果没有,则将整行添加到新表中。

 // Clone() only clones the table structure. It does not also clone the data. DataTable dtFinal = dtOriginal.Clone(); for (int i = 0; i < dtOriginal.Rows.Count; i++) { bool isDupe = false; for (int j = 0; j < dtFinal.Rows.Count; j++) { if (dtOriginal.Rows[i][0].ToString() == dtFinal.Rows[j][0].ToString() && dtOriginal.Rows[i][1].ToString() == dtFinal.Rows[j][1].ToString() && dtOriginal.Rows[i][2].ToString() == dtFinal.Rows[j][2].ToString()) { dtFinal.Rows[j][3] = int.Parse(dtFinal.Rows[j][3].ToString()) + int.Parse(dtOriginal.Rows[i][3].ToString()); isDupe = true; break; } } if (!isDupe) { dtFinal.ImportRow(dtOriginal.Rows[i]); } } 

您可以对此进行扩展,以在匹配条件和添加逻辑中包含更多/更少的列。 您可能还想到要删除列号硬编码,例如将它们迭代到特定索引或其他东西。 这一切都取决于您的要求。 这应该会给你一个不错的起点。

使用linq尝试此代码:

  DataTable dataTable1 = new DataTable(); dataTable1.Columns.Add(new DataColumn("Column1", typeof(int))); dataTable1.Columns.Add(new DataColumn("Column2", typeof(int))); dataTable1.Columns.Add(new DataColumn("Column3", typeof(int))); dataTable1.Columns.Add(new DataColumn("Column4", typeof(int))); dataTable1.Columns.Add(new DataColumn("Column5", typeof(decimal))); dataTable1.Columns.Add(new DataColumn("Column6", typeof(decimal))); dataTable1.Rows.Add(123456, 6, 54, 5, 0, 36.78); dataTable1.Rows.Add(123456, 6, 54, 5, 21, 0); dataTable1.Rows.Add(123456, 6, 54, 8, 0, 102.09); dataTable1.Rows.Add(123456, 6, 54, 8, 6.50, 0); //Select the rows where columns 1-4 have repeated same values var distinctRows = dataTable1.AsEnumerable() .Select(s => new { unique1 = s.Field("Column1"), unique2 = s.Field("Column2"), unique3 = s.Field("Column3"), unique4 = s.Field("Column4"), }) .Distinct(); //Create a new datatable for the result DataTable resultDataTable = dataTable1.Clone(); //Temporary variables DataRow newDataRow; IEnumerable results; decimal tempCol5; decimal tempCol6; //Go through each distinct rows to gather column5 and column6 values foreach (var item in distinctRows) { //create a new row for the result datatable newDataRow = resultDataTable.NewRow(); //select all rows in original datatable with this distinct values results = dataTable1.Select().Where( p => p.Field("Column1") == item.unique1 && p.Field("Column2") == item.unique2 && p.Field("Column3") == item.unique3 && p.Field("Column4") == item.unique4); //Preserve column1 - 4 values newDataRow["Column1"] = item.unique1; newDataRow["Column2"] = item.unique2; newDataRow["Column3"] = item.unique3; newDataRow["Column4"] = item.unique4; //store here the sumns of column 5 and 6 tempCol5 = 0; tempCol6 = 0; foreach (DataRow dr in results) { tempCol5 += (decimal)dr["Column5"]; tempCol6 += (decimal)dr["Column6"]; } //save those sumns in the new row newDataRow["Column5"] = tempCol5; newDataRow["Column6"] = tempCol6; //add the row to the result dataTable resultDataTable.Rows.Add(newDataRow); } 

我建议看一下使用DataTableExtensions,它允许你使用LINQ加入2个数据表来填充最终的数据表。

我需要等到今晚才能发布任何示例代码,但我觉得在此之前你将能够找出所需的LINQ语法。

http://msdn.microsoft.com/en-us/library/system.data.datatableextensions(v=vs.110).aspx

您可以使用LINQ-To-DataTable ,尤其是Enumerable.GroupBy 。 您必须使用匿名类型进行分组,并使用循环来创建具有唯一值的新表。

我使用Enumerable.Sum来获取最后两列的总和:

 Dim first4ColGroups = From row In table Let first4colums = New With { Key .col1 = row.Field(Of Int32)(0), Key .col2 = row.Field(Of Int32)(1), Key .col3 = row.Field(Of Int32)(2), Key .col4 = row.Field(Of Int32)(3) } Group row By first4colums Into RowGroup = Group Dim tblUnique = table.Clone() ' creates an empty table with the same columns ' For Each grp In first4ColGroups Dim row As DataRow = tblUnique.Rows.Add() row.SetField(0, grp.first4colums.col1) row.SetField(1, grp.first4colums.col2) row.SetField(2, grp.first4colums.col3) row.SetField(3, grp.first4colums.col4) row.SetField(4, grp.RowGroup.Sum(Function(r) r.Field(Of Decimal)(4))) row.SetField(5, grp.RowGroup.Sum(Function(r) r.Field(Of Decimal)(5))) Next 

我不知道你想要合并的目的,但这可能有用。

 List list = new List(); System.Data.DataTable DT2 = new System.Data.DataTable(); private void button1_Click(object sender, EventArgs e) { foreach (DataRow row in DT2.Rows) { for (int i = 0; i < DT2.Rows.Count; i++) { var Tjek = DT2.Rows[i][0]; if (list.Contains(DT2.Rows[i][0])) { } else { list.Add(Tjek); } } } }