Linq将(或)将两个数据表合并为一个

我在通过在C#中使用Linq将两个数据表中的正确数据合并为一个数据库时遇到了问题。
我的数据表的数据来自Excel文件读取(而不是数据库)。

我已经尝试了下面的LINQ,但返回行数并不是我想要的(我的目标是检索所有数据,但为了验证,我正在检查行数,以便我可以知道它是正确的还是不容易)。

在dt1中,我有2645条记录。
在dt2中,我有2600条记录。

返回行数是2600(看起来它正在做正确的连接逻辑)。

var v1 = from d1 in dt1.AsEnumerable()
         from d2 in dt2.AsEnumerable()
         .Where(x => x.Field<string>(X_ITEM_CODE) == d1.Field<string>(X_NO) 
         || x.Field<string>(X_ITEM_KEY) == d1.Field<string>(X_NO))
         select dt1.LoadDataRow(new object[] 
         { 
             // I use short cut way instead of Field<string> for testing purpose.
             d1[X_NO],
             d2[X_ITEM_CODE] == null ? "" : d2[X_ITEM_CODE] ,
             d2[X_ITEM_KEY] == null ? "" : d2[X_ITEM_KEY],
             d2[X_COSTS],
             d2[X_DESC],
             d2[X_QTY]== null ? 0 : dt[X_QTY]
         }, false);

         dt1 = v1.CopyToDataTable();
         Console.WriteLine(dt1.Rows.Count);


我试图使用'join',但我的问题是X_NO值可以在X_ITEM_CODE或X_ITEM_KEY中,所以我只能将一个条件放入ON xxx等于yyy。

如果我的上述条件适合使用,我想尝试“加入”。 请给我一些指导。 谢谢。

[附加信息]
我已经尝试foreach循环+ dt1.Select(xxxx)+ dt1.Rows.Add(xxx),它运行良好,但大约2分钟才能完成这项工作。
我正在寻找一种更快的方式,并从我尝试的Linq代码上面看,它比我的foreach循环更快,所以我想给Linq一个机会。
为了演示目的,我只在上面的例子中放了几列,我的实际列数是12列。

我害怕我的帖子会变得很长,如果我把我的foreach循环,所以当我发布这个问题时,我跳过它。
无论如何,下面是代码和示例数据。 对于那些可以编辑并且认为它太长的人,请善意取出不必要/不相关的代码或行。

DataRow[] drs = null;
DataRow drO = null;

foreach (DataRow drY in dt2.Rows)
{
    drs = null;
    drs = dt1.Select(X_NO + "='" + drY[X_ITEM_KEY] + "' OR " + X_NO + "='" + drY[X_ITEM_CODE] + "'");
    if (drs.Length >= 0)
    {
        // drs Leng will always 1 because no duplicate.
        drs[0][X_ITEM_CODE] = drY[X_ITEM_CODE];
        drs[0][X_ITEM_KEY] = drY[X_ITEM_KEY];
        drs[0][X_COST] = clsD.GetInt(drY[X_COST]);      // If null, return 0.
        drs[0][X_DESC] = clsD.GetStr(drY[X_DESC]);      // If null, return "".
        drs[0][X_QTY] = clsD.GetInt(drY[X_QTY]);
    }
    else
    {
        // Not Found in ITEM CODE or KEY, add it.
        drO = dtOutput.NewRow();
        drO[X_ITEM_CODE] = drY[X_ITEM_CODE];
        drO[X_ITEM_KEY] = drY[X_ITEM_KEY];
        drO[X_COST] = clsD.GetInt(drY[X_COST]);
        drO[X_DESC] = clsD.GetStr(drY[X_DESC]);
        drO[X_QTY] = clsD.GetInt(drY[X_QTY]);
        dt1.Rows.Add(drO);
    }
}
// Note: For above else condition, I didn't put in my Linq testing yet.
// If without else condition, my dt1 will still have same record count.

[dt1数据]
X_NO,X_ITEM_CODE,X_ITEM_KEY,成本,DESC,数量,...
AA060210A ,,,,,, ....
AB060220A ,,,,, ....
AC060230A ,,,,, ....
AD060240A ,,,,, ....


[dt2数据]
X_ITEM_CODE,X_ITEM_KEY,成本,DESC,数量
AA060210A,AA060211A,100.00,PART1,10000
AB060221A,AB060220A,120.00,PART2,500
AC060232A,AC060230A,150.00,PART3,100
AD060240A,AD060243A,4.50,PART4,15250

[更新2]
我在“连接”下尝试,它什么也没有返回。 那么,我能否认为加入也无济于事?

var vTemp1 = from d1 in dt1.AsEnumerable()
             join d2 in dt2.AsEnumerable()
             on 1 equals 1
             where (d1[X_NO] == d2[X_ITEM_CODE] || d1[X_NO] == d2[X_ITEM_KEY])
             select dt1.LoadDataRow(new object[] 
             { 
                d1[X_NO],
                d2[X_ITEM_CODE] == null ? "" : d2[X_ITEM_CODE] ,
                d2[X_ITEM_KEY] == null ? "" : d2[X_ITEM_KEY],
                d2[X_COST],
                d2[X_DESC],
                d2[X_QTY]== null ? 0 : d2[X_QTY]
             }, false);

Console.WriteLine(vTemp1.Count()); // return zero.

LINQ只支持equijoins,所以显然join运算符是不能使用的。 但是,对于笛卡尔产品使用LINQ查询,并且where不会提供任何性能改进。

你真正需要的是(LINQ或不)是dt1[X_NO]字段的快速查找。 正如你所说的那样,它是独一无二的,你可以为此构建和使用一本字典:

var dr1ByXNo = dt1.AsEnumerable().ToDictionary(dr => dr.Field<string>(X_NO));

然后像这样修改你的过程:

foreach (DataRow drY in dt2.Rows)
{
    if (dr1ByXNo.TryGetValue(drY.Field<string>(X_ITEM_KEY), out dr0) ||
        dr1ByXNo.TryGetValue(drY.Field<string>(X_ITEM_CODE), out dr0)) 
    {
        dr0[X_ITEM_CODE] = drY[X_ITEM_CODE];
        dr0[X_ITEM_KEY] = drY[X_ITEM_KEY];
        dr0[X_COST] = clsD.GetInt(drY[X_COST]);      // If null, return 0.
        dr0[X_DESC] = clsD.GetStr(drY[X_DESC]);      // If null, return "".
        dr0[X_QTY] = clsD.GetInt(drY[X_QTY]);
    }
    else
    {
        // Not Found in ITEM CODE or KEY, add it.
        drO = dtOutput.NewRow();
        drO[X_ITEM_CODE] = drY[X_ITEM_CODE];
        drO[X_ITEM_KEY] = drY[X_ITEM_KEY];
        drO[X_COST] = clsD.GetInt(drY[X_COST]);
        drO[X_DESC] = clsD.GetStr(drY[X_DESC]);
        drO[X_QTY] = clsD.GetInt(drY[X_QTY]);
        dt1.Rows.Add(drO);
    }
}

由于您在此过程中向dt1添加了新记录,根据您的要求,您可能需要在else (在dt1.Rows.Add(drO); line)之后添加以下内容

dr1ByXNo.Add(dr0.Field<string>(X_NO), dr0);

我没有包含它,因为我没有看到你的代码设置了新的记录X_NO字段,所以上面将产生重复的键异常。

链接地址: http://www.djcxy.com/p/53749.html

上一篇: Linq to combine (or) join two datatables into one

下一篇: Multiple on clause from DataTable to DataTable via LINQ