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