【发布时间】:2019-06-24 08:53:35
【问题描述】:
我有数据表形式的传入数据。没有可以依赖的静态类。我有 2 张桌子,客户和计费。有7000个客户,1200条计费记录。
所有客户记录都有一个“ResponsiblePartyID”,多个客户可以有同一个ID,它引用了计费表的ID。
DataTable customer= ETL.ParseTable("customer"); // 7000 records
DataTable billing= ETL.ParseTable("billing"); // 1200 records
var JoinedTables = (from c in customer.AsEnumerable()
join p in billing.AsEnumerable() on (string) c["ResponsiblePartyID"] equals (string) p["ID"] into ps
from p in ps.DefaultIfEmpty()
select new {c, p}
);
所以这不能正常工作,即使它以错误的格式输出结果我也会很高兴,但它只返回 2200 个结果而不是 7000 个。
如果它只返回 1200,或者如果它返回全部 7000,似乎是有道理的,但 2200 是一个奇怪的地方让它停下来。
我手动解析二进制数据作为我的数据源,我选择了一个 DataTable 作为目标,因为它似乎是正确的方法,但是在处理了 Linq 并尝试进行连接之后,我想知道我是否应该重新考虑一下。
Linq 似乎不是为查询 DataTables 而设计的,因为我必须对所有内容执行 .AsEnumerable(),然后在完成每个步骤时使用 .CopyToDataTable()。
我没有为我的所有数据定义静态类,因为每个值的属性都已在 DataTable 中定义,那么获取 2 个 DataTables 的“正确”方式是什么,进行 LEFT JOIN(如 SQL)左边的结果没有被右边的结果排除在哪里?如果我从左边的一个表开始,有 7000 行,我想以 7000 结束。如果没有匹配的记录,用 null 填充它。
我不想定义每一列,它应该返回一个扁平的 Array / DataTable - 像这样:
var JoinedTables = (from c in customer.AsEnumerable()
join p in billing.AsEnumerable() on (string) c["ResponsiblePartyID"] equals (string) p["ID"] into ps
from p in ps.DefaultIfEmpty()
select ALL_COLUMNS
);
更新:
我使用了在 cmets (Linq return all columns from all tables in the join) 中链接的 Jon Skeet 答案中的示例,他的解决方案确实与我的第一次尝试没有什么不同,它仍然没有解决如何将结果扁平化为单个 DataTable .这是数据和当前输出的示例:
Customers
ID Resp_ID Name
1 1 Fatafehi
2 2 Dan
3 1 Anthony
4 1 Sekona
5 1 Osotonu
6 6 Robert
7 1 Lafo
8 1 Sarai
9 9 Esteban
10 10 Ashley
11 11 Mitch
12 64 Mark
13 11 Shawn
14 53 Kathy
15 53 Jasmine
16 16 Aubrey
17 17 Peter
18 18 Eve
19 19 Brenna
20 20 Shanna
21 21 Andrea
Billing
ID 30_Day 60_Day
2 null null
6 null null
9 null null
10 null null
11 null null
64 null null
53 null null
16 null null
17 null null
18 null null
19 null null
20 -36.52 null
21 1843.30 null
Output:
2 2 Dan 2 null null
6 6 Robert 6 null null
9 9 Esteban 9 null null
10 10 Ashley 10 null null
11 11 Mitch 11 null null
12 64 Mark 64 -131.20 null
13 11 Shawn 11 null null
14 53 Kathy 53 null null
15 53 Jasmine 53 null null
16 16 Aubrey 16 null null
17 17 Peter 17 null null
18 18 Eve 18 null null
19 19 Brenna 19 null null
20 20 Shanna 20 -36.52 null
21 21 Andrea 21 1843.30 null
请注意,结果中缺少 Resp_ID 为 1 的任何人。为了显示输出,我使用了以下内容,然后插入了 null 值进行可视化:
foreach (var row in joinedRows)
{
Console.WriteLine(row.r1["ID"] + " " + row.r1["Resp_ID"] + " " + row.r1["Name"] + " " + row.r2["ID"] + " " + row.r2["30_Day"] + " " + row.r2["60_Day"]);
}
【问题讨论】:
-
解决此类问题的一种方法是找到一个反例 - 即数据库中的一个示例,其中包含您认为应该是连接的一部分但不是连接的两条记录。如果仔细查看反例不能单独回答您的问题,您甚至可以创建一组仅包含这两条记录的简单测试表并尝试调试这种情况。
-
谢谢大家,我用示例数据更新了我的问题