1

我有两个数据表。我想合并它们,并且只想从两个数据表中获取不匹配的行。有人可以帮忙吗?

目前我正在使用以下代码,但它没有返回任何内容:

Actual_Table = myDataSet_Actual.Tables("Actuals")
Planned_Table = myDataset_Planned.Tables("Planned")

Planned_Table.AcceptChanges()
Planned_Table.Merge(Actual_Table, False)

change = Planned_Table.GetChanges(DataRowState.Added)
DGV1.DataSource = change ' DGV1= Data grid view
4

2 回答 2

1

TL;博士

您可以使用以下代码执行此操作,但请继续阅读以了解更多详细信息:

change = Planned_Table.AsEnumerable _
                      .Except(Actual_Table.AsEnumerable, DataRowComparer.Default) _ 
                      .CopyToDataTable

这里有几点需要注意:

正如在这个 SO question中指出的那样,DataTable.Merge不会改变行状态,所以寻找行DataRowState.Added总是空的。

此外,Merge将第二个表中的每一行添加到第一个表中,因此即使 RowState更改,第二个表中的所有内容也会出现。

最后,假设我们只将第二个数据表中的唯一值添加到第一个数据表中,我们只会取回第二组中的元素,而不是第一组中的元素。也许这就是你想要的,但如果你真的想要其中一个,我会描述这两个选项。

我们需要的工具

正如在此处此处的其他 SO 问题中发现的那样,我们可以使用以下任何一种找到正确的条目集LINQ Set Operations

您可以在 MSDN 中进一步探索这些中的每一个,但正如此SO Question中提到的,仅供参考,Union并且Concat都会将一个可枚举附加到另一个上,但 Union 将删除重复项(在检查DataRows 的相等性时,您必须传入重载IEqualityComparer= DataRowComparer.Default)

此外,我们还想枚举一个 DataTable,所以要做到这一点,我们需要AsEnumerable从命名空间调用该方法DataTableExtensions

解决方案设置

就像我们正在查看相同的代码一样,这里有一些基本的数据表,我们可以在这些数据表上执行集合操作

Dim dt, dataTable1, dataTable2 As New DataTable

With dt.Columns
    .Add("ID", GetType(Integer))
    .Add("Name", GetType(String))
End With

dataTable1 = dt.Clone
dataTable2 = dt.Clone

With dataTable1.Rows
    .Add(1, "Tod")
    .Add(2, "Jim")
End With

With dataTable2.Rows
    .Add(2, "Jim")
    .Add(3, "Han")
End With

解决方案集

因此,如果您只想要第二个表中未出现在第一个表中的新项目,那么您需要Right Outer Join

右外连接

如果您想要两组之间不同的所有数据,您需要Full Outer Join排除Inner Join

右外连接

您可以在这篇 Jeff Atwood帖子中阅读有关不同集合和创建它们的连接的更多信息。

代码

如果你想要第一个选项,你可以通过调用Except第二个Datatable并传入第一个来获取第二个集合中的元素

Dim just2 As DataTable
just2 = dataTable2.AsEnumerable _
                  .Except(dataTable1.AsEnumerable, DataRowComparer.Default) _
                  .CopyToDataTable()

输出将是:

| ID | Name |
| 3  | Han  |

如果您想要每组中的唯一值,则必须调用 distinct 两次,然后加入这两个值。我们不需要将 传递DataRowComparer给该Union方法,因为我们已经保证两个表中没有重复项

Dim just1 As IEnumerable(Of DataRow)
Dim just2 As IEnumerable(Of DataRow)
Dim union As DataTable

'get rows that are only in table1
just1 = dataTable1.AsEnumerable.Except(dataTable2.AsEnumerable, DataRowComparer.Default)

'get rows that are only in table2
just2 = dataTable2.AsEnumerable.Except(dataTable1.AsEnumerable, DataRowComparer.Default)

'get all unique rows
union = just1.Union(just2).CopyToDataTable

由于我们不需要单独的唯一元素集,因此无需调用CopyToDataTablejust 以便我们可以重新转换为IEnumerable(Of DataRow)withAsEnumerable

联合的输出将是:

| ID | Name |
| 1  | Tod  |
| 3  | Han  |
于 2013-05-24T17:11:00.397 回答
0

我希望这对你有帮助:http: //www.dotnetperls.com/datatable-compare-rows

在示例中,它在控制台中写入比较结果,但我想你可以做到这一点;)

祝你好运!

编辑:实际上,如果您DataTable的 s 具有相同的行数并且您正在一对一地比较行,您应该更改For Each一个语句的For语句。就像是:

For i As Integer = 0 To RowNo - 1
    'compare datatable1_row(i) with datatable2_row(i) and do the magic
Next
于 2012-11-07T21:42:26.743 回答