有没有一种方法可以合并两个DataTable并仅保留特定列的更改?

时间:2019-04-08 15:15:02

标签: c# winforms merge datatable

我有以下两个表,这些表是从Excel文件导入到Windows Forms应用程序中的。这些文件是自动创建的,很遗憾,无法更改它们。我简化了下面的所有示例。实际上,这些表有40多个列,每个都有10万多行。

第一张表包含客户帐单信息,其中customer是客户编号,我将其用作主键。

BillingTable

Customer(PK)      Name        Address      Type
------------  -------------  ----------  -----------
1               Customer 1    Address 1    Billing    
2               Customer 2    Address 2    Billing
3               Customer 3    Address 3    Billing

第二个表包含客户发货信息,并具有另一个客户编号。 “合作伙伴”列引用了结算信息:

ShippingTable

Customer     Name         Address        Type      Partner(PK)
--------- -----------  --------------  ---------- ------------
4          Customer 1    Sh.Address 1   Shipping      1
5          Customer 2    Sh.Address 2   Shipping      2
6          Customer 4    Sh.Address 4   Shipping      6

如您所见,开票信息表中有一些发货信息表中未引用的条目。还会发生这样的情况:客户有发货信息,但没有帐单信息。在这种情况下,合作伙伴列包含发货信息表中的客户编号。

我必须将两个表合并为以下内容:

ResultTable

Customer(PK)     Shipping      Name         Address        Type
-------------  -----------  ------------  ------------  ----------
1                   4        Customer 1    Address 1      Billing
2                   5        Customer 2    Address 2      Billing
3                            Customer 3    Address 3      Billing
6                   6        Customer 4    Sh.Address 4   Shipping

因此,我需要一个表,其中仅将运输客户编号添加到计费表中(如果有的话)。如果不是,则运送栏可以保持空白。如果有发货信息但没有帐单信息,我想从ShippingTable中获取整行。

仅使用DataTable.Merge()之类的BillingTable.Merge(ShippingTable)方法时,发货信息将覆盖开票表的地址和类型列。当像BillingTable.Merge(ShippingTable, true)一样将prepareChanges设置为true时,它不会将运送客户编号合并到BillingTable中,而只是将其他运送客户信息添加到该表中。

我还尝试通过循环遍历它们并使用Linq获取所需的运输信息来“手动”获得每一行的运输编号。但是,由于我要处理大量的行,因此这确实需要非常长的时间。

我接下来要尝试的是在合并之前从ShippingTable中删除“地址和类型”列。但是,在这种情况下,我当然会丢失没有帐单信息的客户的信息。

因此,总结一下,这是我到目前为止尝试过的:

BillingTable.Merge(ShippingTable); // Billing info is overwritten

BillingTable.Merge(ShippingTable, true); // Does not merge shipping number

// Loop through each row, takes very long 
foreach(DataRow row in BillingTable.Rows) {

    row["Shipping"] = ShippingTable.Rows.Cast<DataRow>()
                                   .Where(shRow => shRow["Partner"].ToString() == row["Customer"])
                                   .First()
                                   .Field<string>("Customer");
}

// Delete Address and Type columns before merging
// Does not include address and type information for shipping only entries
ShippingTable.Columns.Remove("Address");
ShippingTable.Columns.Remove("Type");

BillingTable.Merge(ShippingTable);

结果在这里:

使用BillingTable.Merge(ShippingTable)

Customer(PK)     Shipping      Name         Address        Type
-------------  -----------  ------------  -------------  ---------
1                   4        Customer 1    Sh.Address 1   Shipping
2                   5        Customer 2    Sh.Address 2   Shipping
3                            Customer 3     Address 3     Billing
6                   6        Customer 4    Sh.Address 4   Shipping

With BillingTable.Merge(ShippingTable,true)

Customer(PK)     Shipping      Name         Address        Type
-------------  ------------ ------------  -------------  ---------
1                            Customer 1    Address 1      Billing
2                            Customer 2    Address 2      Billing
3                            Customer 3     Address 3     Billing
6                   6        Customer 4    Sh.Address 4   Shipping

在合并之前从ShippingTable中删除“地址”和“类型”列时:

Customer(PK)     Shipping      Name         Address        Type
-------------  -----------  ------------  ------------  ----------
1                   4        Customer 1    Address 1      Billing
2                   5        Customer 2    Address 2      Billing
3                            Customer 3    Address 3      Billing
6                   6        

因此,或者有一种方法可以合并我到目前为止无法找到的表,或者我将不得不以另一种方式来做。我曾考虑过从Excel文件中获取表时使用SQL来连接表,或者使用Linq代替DataTable.Merge()来连接表,但是我无法以任何一种方式正常工作。

请问有人可以帮忙吗?

(抱歉,详细说明)

1 个答案:

答案 0 :(得分:0)

很好,看来解决方案很容易让我想到。

我只是简单地切换了表格,然后进行了DataTable.Merge()的操作。因此,解决方案将是:

ShippingTable.Merge(BillingTable);