更新:忘记提及,该表可能包含多种类型的商品代码
我的数据表有问题。共有14件商品具有相同的商品代码。现在有2张表来自不同的来源。一个按项目代码分组并总结数量,当计数等于10时,转到下一行,每行包含特定信息,如装运和备注。另一个表包含更多详细信息。
Source1:分组表
ItemCode|TotalQty|Shipment|Remarks|Line
=========================================
ITEM01 | 1000 | S001 | R001 | 1 <==10 items here
ITEM01 | 400 | S002 | R002 | 2 <==4 items here
Source2:详情表(14项&amp;行)
RefNo|ItemCode|Quantity|Weight|From
=======================================
R001 | ITEM01 | 100 | 50 | US
R002 | ITEM01 | 100 | 50 | US
R003 | ITEM01 | 100 | 50 | US
. | . | . | . | .
. | . | . | . | .
R013 | ITEM01 | 100 | 50 | US
R014 | ITEM01 | 100 | 50 | US
我想将source1和source2结合起来,得到如下结果
Shipment|Line|Remarks|ItemCode|TotalQty|RefNo|Quantity|Weight|From
===================================================================
S001 | 1 | R001 | ITEM01 | 1000 | R001| 100 | 50 | US \\1
S001 | 1 | R001 | ITEM01 | 1000 | R002| 100 | 50 | US \\2
S001 | 1 | R001 | ITEM01 | 1000 | R003| 100 | 50 | US \\3
S001 | 1 | R001 | ITEM01 | 1000 | R004| 100 | 50 | US \\4
S001 | 1 | R001 | ITEM01 | 1000 | R005| 100 | 50 | US \\5
S001 | 1 | R001 | ITEM01 | 1000 | R006| 100 | 50 | US \\6
S001 | 1 | R001 | ITEM01 | 1000 | R007| 100 | 50 | US \\7
S001 | 1 | R001 | ITEM01 | 1000 | R008| 100 | 50 | US \\8
S001 | 1 | R001 | ITEM01 | 1000 | R009| 100 | 50 | US \\9
S001 | 1 | R001 | ITEM01 | 1000 | R010| 100 | 50 | US \\10
S002 | 2 | R002 | ITEM01 | 400 | R011| 100 | 50 | US \\11
S002 | 2 | R002 | ITEM01 | 400 | R012| 100 | 50 | US \\12
S002 | 2 | R002 | ITEM01 | 400 | R013| 100 | 50 | US \\13
S002 | 2 | R002 | ITEM01 | 400 | R014| 100 | 50 | US \\14
有没有办法(Linq或循环)获得上述结果?谢谢你的帮助!
答案 0 :(得分:0)
可以使用LINQ(我假设您已经完成,因为您已经包含LINQ
标记),但不是我认为的漂亮的时尚。
鉴于两个DataTable
个对象具有上述格式和数据,名为 grouped
和 detail
,这是一个LINQ表达式,将以您希望的方式将数据拼接在一起:
IEnumerable<object[]> qry =
(
from DataRow rDetail in detail.Rows
let dgrp = detail.Rows.IndexOf(rDetail) / 10
join DataRow rGroup in grouped.Rows
on dgrp equals grouped.Rows.IndexOf(rGroup)
orderby rDetail["RefNo"]
select new object[] {
rGroup["Shipment"], rGroup["Line"], rGroup["Remarks"], rGroup["ItemCode"], rGroup["TotalQty"],
rDetail["RefNo"], rDetail["Quantity"], rDetail["Weight"], rDetail["From"]
}
);
现在您需要另一个DataTable
将这些结果输入:
DataTable res = new DataTable();
res.Columns.Add("Shipment", typeof(string));
res.Columns.Add("Line", typeof(Int32));
res.Columns.Add("Remarks", typeof(string));
res.Columns.Add("ItemCode", typeof(string));
res.Columns.Add("TotalQty", typeof(Int32));
res.Columns.Add("RefNo", typeof(string));
res.Columns.Add("Quantity", typeof(Int32));
res.Columns.Add("Weight", typeof(Int32));
res.Columns.Add("From", typeof(string));
最后,在res
表中填写LINQ查询的结果:
foreach (object[] rowdata in qry)
res.Rows.Add(rowdata);
上面的代码适用于这个特定的数据集,但我不能向你保证更多。它在很大程度上依赖于源表中的行顺序,并且因为我使用DataTable.Rows.IndexOf
来获取顺序,所以很可能这对于大量数据集来说非常慢。
但是你已经在使用DataTable
而不是正确输入的集合了,所以无论如何,所有的赌注都在性能和代码完整性的赌注中。
这是我建议不使用LINQ执行任务的一种情况。恕我直言,这将作为迭代循环而不是查询更好地完成。你没有比迭代版本获得更多(如果有的话)改进,你会失去很多清晰度,并且你可以在使用它之前设置好各种各样的乐趣。
因为我不能单独留下,所以这里是一个完整的(很长的代码)解决方案,使用LINQ的组合,用于保存正在处理的数据的类和用于生成表的迭代:
public DataTable MergeShippingData(DataTable groupTable, DataTable detailTable)
{
// convert group table to array of GroupEntry objects
var groupList =
(
from DataRow grouprow in groupTable.Rows
let ent = GroupEntry.FromRow(grouprow)
where ent != null
select ent
).ToArray();
// convert detail table to sequence of DetailEntry objects
var detailSeq =
from DataRow detailrow in detailTable.Rows
let ent = DetailEntry.FromRow(detailrow)
where ent != null
select ent;
// Create output DataTable
DataTable output = CreateOutputTable();
// Process all detail lines into shippings
foreach (var detail in detailSeq)
{
// Find available shipping group for the item code with enough remaining capacity
var grp = groupList.First (g => g.ItemCode == detail.ItemCode && g.Remainder >= detail.Quantity);
if (grp == null)
throw new Exception("No available shipping found for detail item...");
// update remaining space in shipping group
grp.Remainder -= detail.Quantity;
// add data to output table
output.Rows.Add(new object[] {
grp.Shipment, grp.Line, grp.Remarks, grp.ItemCode, grp.TotalQty,
detail.RefNo, detail.Quantity, detail.Weight, detail.From
});
}
return output;
}
// Class to hold the shipping groups while processing
public class GroupEntry
{
// fields from source DataTable
public string ItemCode;
public int TotalQty;
public string Shipment;
public string Remarks;
public int Line;
// process variable, holds remaining quantity value
public int Remainder;
// Convert DataRow into GroupEntry
public static GroupEntry FromRow(DataRow r)
{
try
{
return new GroupEntry
{
ItemCode = r.Field<string>(0),
TotalQty = r.Field<int>(1),
Shipment = r.Field<string>(2),
Remarks = r.Field<string>(3),
Line = r.Field<int>(4),
Remainder = r.Field<int>(1)
};
}
catch { }
return null;
}
}
// Class to hold shipping Detail records during processing
public class DetailEntry
{
public string RefNo;
public string ItemCode;
public int Quantity;
public int Weight;
public string From;
// Convert DataRow into DetailEntry
public static DetailEntry FromRow(DataRow r)
{
try
{
return new DetailEntry
{
RefNo = r.Field<string>(0),
ItemCode = r.Field<string>(1),
Quantity = r.Field<int>(2),
Weight = r.Field<int>(3),
From = r.Field<string>(4)
};
}
catch { }
return null;
}
}
// Create output DataTable
public DataTable CreateOutputTable()
{
DataTable res = new DataTable();
res.Columns.Add("Shipment", typeof(string));
res.Columns.Add("Line", typeof(Int32));
res.Columns.Add("Remarks", typeof(string));
res.Columns.Add("ItemCode", typeof(string));
res.Columns.Add("TotalQty", typeof(Int32));
res.Columns.Add("RefNo", typeof(string));
res.Columns.Add("Quantity", typeof(Int32));
res.Columns.Add("Weight", typeof(Int32));
res.Columns.Add("From", typeof(string));
return res;
}
添加一些错误处理,你就可以了。